2017北京国庆刷题Day5 morning
期望得分:0+60+60=120
实际得分:0+30+60=90
令g=gcd(X11,X12,X13……)
则行列式可能为D的充要条件为g|D
1、g|D为必要条件:
由定义来算行列式的时候,每一项都要从第一行里取一个数,所以g|D
2、g|D为充分条件:
首先可以通过矩阵的初等变换,将矩阵X消成对角矩阵
其中,X11* X22 * X33* X44=D
上述矩阵等价于
把D拆为g*D/g
还原到矩阵中
即
X22=
此矩阵模拟先前初等变换即可还原为原矩阵X
#include <algorithm> #include <cstdio> #include <cstdlib> #include <iostream> #include <cmath>using namespace std;int gcd(int a,int b) { return !b ? a : gcd(b,a%b); }bool solve() {int n,m,x,y; scanf("%d%d",&n,&m);x=0;for (int i=1;i<=n;++i) {scanf("%d",&y);x=gcd(x,abs(y));}if (n==1) return y==m;if (!x) return !m;return !(abs(m)%x); }int main() {freopen("det.in","r",stdin);freopen("det.out","w",stdout);int t;scanf("%d", &t);while(t--)if (solve()) printf("Y\n");else printf("N\n"); }
View Code
每次分两半的时候,一定是奇数在左边,偶数在右边
所以用类似于线段树的思想来分治
由于每次讲将序列按奇偶下标分成两半,如果每次处理分成的那一半区间
那这个区间一定是一个等差数列,且公差为 2^d
所以
如果我们将区间离散化为1,2,3,……
那么完全可以求出区间离散化之后的答案,在回溯往上的时候每次*2(奇数*2-1),便可得到原区间的答案
例:1 2 3 4 5 6 7
第一次分治:
原左区间: 1 3 5 7 原右区间 2 4 6
离散化后区间 1 2 3 4 1 2 3
离散化后左区间 总和 1+2+3+4=10
当回溯到上一层是,实际上是(1*2-1)+(2*2-1)+(3*2-1)+(4*2-1)= 10*2-4=16
离散化后右区间 总和 1+2+3=6
当回溯到上一层是,实际上是 (1*2)+(2*2)+(3*2)=6*2=12
具体怎么求?
设当前分治到 rr,l,r,x,y
表示当前区间离散化后为[1,2,……rr],当前要求下标在本区间的[l,r]内,大小 在 本区间离散化后[x,y]之间
分四种情况:
1、对答案有贡献的数全在当前区间内,即 l=1 && r=rr
因为每次分治的区间是一个等差数列,根据求和公式,本区间的答案为(y-x+1)*(x+y)/2
2、对答案有贡献的数是当前区间的一部分且全在左区间,即r<=mid ,那就递归到左区间求解
在左区间中 ,rr变成mid,l,r 不变,x变为x/2+1,y变为(y+1)/2
3、对答案有贡献的数是当前区间的一部分且全在右区间,即l>mid,那就递归到右区间求解
在右区间中,rr变成rr-mid,l-=mid,r-=mid,x变为(x+1)/2,y变为y/2+1
4、对答案有贡献的数是当前区间的一部分且左右区间都有,左右区间都递归,再合并
这里 l,r 根上面的左右区间有所不同
左区间的r是mid,右区间的l是1
上面提到了左区间是奇数,回溯的时候 和变为*2-元素个数
所以 回溯时,除了返回 和,还要返回元素个数
用pair即可
小细节:等差数列求和的时候,(y-x+1)*(x+y)/2 乘法运算可能会爆long long
所以 判断哪个是偶数,先进行除法运算
#include<cstdio> #include<iostream>#define mp(a,b) make_pair((a),(b))using namespace std;typedef long long LL; typedef pair<LL,LL>pr;LL mod;void read(LL &x) {x=0; char c=getchar();while(!isdigit(c)) c=getchar();while(isdigit(c)) { x=x*10+c-'0'; c=getchar(); } }pr solve(LL rr,LL l,LL r,LL x,LL y) {if(x>rr || l>r) return mp(0,0);if(l==1 && r==rr){y=min(y,rr);LL s;if (!((x+y)&1))s=(x+y>>1)%mod*((y-x+1)%mod)%mod;else s=((x+y)%mod)*((y-x+1>>1)%mod)%mod;return mp(s,(y-x+1)%mod);}LL mid=rr+1>>1;if(r<=mid) {pr res=solve(mid,l,r,(x>>1)+1,y+1>>1);return mp(((res.first<<1)-res.second)%mod,res.second);}if(l>mid){pr res=solve(rr-mid,l-mid,r-mid,x+1>>1,y>>1);return mp((res.first<<1)%mod,res.second);}pr res1=solve(mid,l,mid,(x>>1)+1,y+1>>1);pr res2=solve(rr-mid,1,r-mid,x+1>>1,y>>1);return mp(((res1.first<<1)-res1.second+(res2.first<<1))%mod,(res1.second+res2.second)%mod); }int main() {freopen("seq.in","r",stdin);freopen("seq.out","w",stdout);LL n,m;read(n); read(m); read(mod);LL l,r,x,y;while(m--){read(l); read(r); read(x); read(y);pr ans=solve(n,l,r,x,y);printf("%I64d\n",(ans.first+mod)%mod);} }
View Code
考场 30分 莫队 ,然而枚举有60
#include<cmath> #include<cstdio> #include<iostream> #include<algorithm> #define N 100001 #define lowbit(x) x&(-x) using namespace std; typedef long long LL; int a[N],n,m,mod; int bl[N]; LL c[N],ans[N]; struct node {int l,r,x,y,id; }e[N]; void read(int &x) {x=0; char c=getchar();while(!isdigit(c)) c=getchar();while(isdigit(c)) { x=x*10+c-'0'; c=getchar(); } } void dfs(int l,int r,int k) {if(l==r) return;int m=l+r>>1,t=m;dfs(l,m,k<<1);for(int i=l;i<=m;i++) if(a[i]+k<=n) a[++t]=a[i]+k; } bool cmp(node p,node q) {if(bl[p.l]!=bl[q.l]) return bl[p.l]<bl[q.l];return p.r<q.r; } void add(int x,int w) {while(x<=n) { c[x]+=w; x+=lowbit(x); } } LL query(int x) {LL sum=0;while(x) { sum+=c[x]; x-=lowbit(x); }return sum; } void update(int pos,bool ty) {if(ty) add(a[pos],a[pos]);else add(a[pos],-a[pos]); } int main() {freopen("seq.in","r",stdin);freopen("seq.out","w",stdout);read(n); read(m); read(mod);a[1]=1; dfs(1,n,1);for(int i=1;i<=m;i++) {read(e[i].l),read(e[i].r),read(e[i].x),read(e[i].y);if(e[i].x>n) e[i].x=n;if(e[i].y>n) e[i].y=n;e[i].id=i;}int siz=sqrt(n);for(int i=1;i<=n;i++) bl[i]=(i-1)/siz+1;sort(e+1,e+m+1,cmp);int L=1,R=0,l,r;for(int i=1;i<=m;i++){l=e[i].l; r=e[i].r;while(L<l) update(L++,0);while(L>l) update(--L,1);while(R<r) update(++R,1);while(R>r) update(R--,0);if(e[i].x>1) ans[e[i].id]=query(e[i].y)-query(e[i].x-1);else ans[e[i].id]=query(e[i].y);}for(int i=1;i<=m;i++) printf("%I64d\n",ans[i]%mod); }
View Code
树形DP+倍增
回想倍增法求LCA的过程
从大到小枚举k,每次跳2^k步,只要不越界就跳,最后一定能跳到LCA
因为跳的都是2的幂次步,所以每跳一步就是二进制加了一个1
先预处理fa[i][k],表示点i向上跳2^k 步的祖先节点
设 f[i][j] 表示最后一步跳了2^j步,跳到了点i的答案之和
cnt[i][j] 表示最后一步跳了2^j步,跳到了点i的方案数
因为有了倍增求lCA原理的保证,所以只需要考虑跳2的幂次步
设siz[i]表示以i为根的子树的大小
rt[i]=j 表示 当前点属于 i的子树里,以j为根节点的子树
假设dfs回溯到x,转移分两种:
1、以x为链的一个端点
枚举x向上跳2^k次,则v=fa[x][j]
那么ans+=siz[v]-siz[rt[v]] ——所有非rt[v]子树的点,与x的LCA都是v,都会有1的贡献
(类似于点分治中要去除同一子树内合法的点)
cnt[v][k]++ f[v][k]++
2、x作为倍增过程中的一个中途点
那么枚举最后一步跳了2^i 跳到了x
枚举x再往上跳2^j步,则v=fa[x][j]
那么ans+=(f[x][i]+cnt[x][i])*(siz[v]-siz[rt[v]])
f[x][i] 是原来的答案,在以v做LCA时,又会用 (siz[v]-siz[rt[v]])次
cnt[x][i] 是 要再往上跳2^j步,又有一个1的贡献
cnt[v][j]+=cnt[x][i] f[v][j]+=f[x][i]+cnt[x][i]
例:1--2--3--4 如果4到1的距离为3,二进制为11,对答案的贡献为2
回溯到4的时候,以4为端点会累积3--4 2--4
回溯到3的时候,以3为端点会累积2--3 1--3
回溯到2的时候,以2为端点会累积1--2,以2为中途点会累积1--2--3--4
(4跳2^1累积到2里,然后在枚举2为中途点时,最后一步跳了2^1到2,2再往上跳2^0)
为什么在枚举3作为中途点的时候,不枚举跳了2^0次方到了3
因为此时3不是中途点,我们是按跳2^k,k是降序跳的
个人总结:支持本题不重不漏的原理就是倍增求LCA的原理
或者是说任意数可以拆为2^k1+2^k2+2^k3…… ki 依次递减
个人AC代码
#include<cstdio> #define N 100001using namespace std;typedef long long LL;LL ans;int front[N],nxt[N<<1],to[N<<1],tot; int fa[N][17],siz[N],rt[N]; int cnt[N][17],f[N][17];void add(int u,int v) {to[++tot]=v; nxt[tot]=front[u]; front[u]=tot;to[++tot]=u; nxt[tot]=front[v]; front[v]=tot; }void dfs1(int x,int y) {fa[x][0]=y; siz[x]=1;for(int i=1;i<=16;i++) fa[x][i]=fa[fa[x][i-1]][i-1];for(int i=front[x];i;i=nxt[i])if(to[i]!=y) dfs1(to[i],x),siz[x]+=siz[to[i]]; }void dfs2(int x) {for(int i=front[x];i;i=nxt[i])if(to[i]!=fa[x][0]) rt[x]=to[i],dfs2(to[i]);for(int i=0;i<=16;i++){ans+=siz[fa[x][i]]-siz[rt[fa[x][i]]];cnt[fa[x][i]][i]++;f[fa[x][i]][i]++;}for(int i=1;i<=16;i++)for(int j=0;j<i;j++){ans+=LL(cnt[x][i]+f[x][i])*LL(siz[fa[x][j]]-siz[rt[fa[x][j]]]);cnt[fa[x][j]][j]+=cnt[x][i];f[fa[x][j]][j]+=f[x][i]+cnt[x][i];} }int main() {freopen("bitcount.in","r",stdin);freopen("bitcount.out","w",stdout);int n;scanf("%d",&n);int u,v;for(int i=1;i<n;i++){scanf("%d%d",&u,&v);add(u,v);}dfs1(1,0);siz[0]=siz[1]; nxt[0]=1;dfs2(1);printf("%I64d",ans); }
View Code
自己加了中间输出辅助理解的std
#include <iostream> #include <cstdio> #include <cstdlib> #include <cstring> #include <string> #include <cmath> #include <vector>#define st first #define nd second using namespace std;struct edge {int x;int nxt; }; typedef long long LL;const int N = 1E5 + 10; edge e[2 * N]; int lca[N][17], hd[N], fa[N], sons[N], nxt[N], cnt[N][17], f[N][17]; int n, m, x, y, l; LL ans;void link(int x, int y) {e[++l].x = y;e[l].nxt = hd[x];hd[x] = l; }void dfs_lca(int x) {lca[x][0] = fa[x];sons[x] = 1;for (int i = 1; i <= 16; ++i)lca[x][i] = lca[lca[x][i - 1]][i - 1];for (int p = hd[x]; p; p = e[p].nxt)if (e[p].x != fa[x]) {fa[e[p].x] = x;dfs_lca(e[p].x);sons[x] += sons[e[p].x];} }void dfs_ans(int x) {for (int p = hd[x]; p; p = e[p].nxt)if (e[p].x != fa[x]) nxt[x] = e[p].x, dfs_ans(e[p].x);for (int i = 0; i <= 16; ++i) {ans += sons[lca[x][i]] - sons[nxt[lca[x][i]]];if(sons[lca[x][i]] - sons[nxt[lca[x][i]]]) printf("%d : sons[%d]-sons[%d]=%d\n",x,lca[x][i],nxt[lca[x][i]],sons[lca[x][i]] - sons[nxt[lca[x][i]]]);cnt[lca[x][i]][i]++;f[lca[x][i]][i]++;}for (int i = 1; i <= 16; ++i)for (int j = 0; j <= i - 1; ++j) {ans += LL(cnt[x][i] + f[x][i]) * LL(sons[lca[x][j]] - sons[nxt[lca[x][j]]]);if(LL(cnt[x][i] + f[x][i]) * LL(sons[lca[x][j]] - sons[nxt[lca[x][j]]]))printf("%d : cnt[%d][%d]+f[%d][%d] * sons[%d]-sons[%d] = %I64d\n",x,x,i,x,i,lca[x][j],nxt[lca[x][j]],LL(cnt[x][i] + f[x][i]) * LL(sons[lca[x][j]] - sons[nxt[lca[x][j]]]));cnt[lca[x][j]][j] += cnt[x][i];f[lca[x][j]][j] += f[x][i] + cnt[x][i];} }int main() {//freopen("bitcount.in", "r", stdin);//freopen("bitcount.out", "w", stdout);scanf("%d", &n);for (int i = 1; i < n; ++i) {scanf("%d%d", &x, &y);link(x, y);link(y, x);}dfs_lca(1);sons[0] = sons[1];nxt[0] = 1;dfs_ans(1);printf("%I64d\n", ans); }
View Code
考场60分暴力
#include<cstdio> #include<algorithm> #define N 2001 using namespace std; int front[N],to[N<<1],nxt[N<<1],tot; int val[N],deep[N],id[N]; int lca[N][N],f[N][12]; int n; void add(int u,int v) {to[++tot]=v; nxt[tot]=front[u]; front[u]=tot;to[++tot]=u; nxt[tot]=front[v]; front[v]=tot; } int cal(int x) {int sum=0;while(x) sum+=(x&1),x>>=1;return sum; } void dfs(int x,int dep,int fa) {id[x]=++tot; deep[x]=dep;f[x][0]=fa;for(int i=front[x];i;i=nxt[i])if(to[i]!=fa) dfs(to[i],dep+1,x); } int getlca(int x,int y) {if(id[x]<id[y]) swap(x,y);for(int i=11;i>=0;i--)if(id[f[x][i]]>id[y]) x=f[x][i];return f[x][0]; } void prelca() {for(int j=1;j<=11;j++)for(int i=1;i<=n;i++)f[i][j]=f[f[i][j-1]][j-1];for(int i=1;i<n;i++)for(int j=i+1;j<=n;j++)lca[i][j]=getlca(i,j); } void solve() {int ans=0;for(int i=1;i<n;i++)for(int j=i+1;j<=n;j++)ans+=val[deep[i]-deep[lca[i][j]]]+val[deep[j]-deep[lca[i][j]]];printf("%d",ans); } int main() {freopen("bitcount.in","r",stdin);freopen("bitcount.out","w",stdout); scanf("%d",&n);int u,v;for(int i=1;i<n;i++) { scanf("%d%d",&u,&v); add(u,v); }for(int i=1;i<=n;i++) val[i]=cal(i);tot=0; dfs(1,0,0);prelca();solve(); }
View Code
转载于:https://www.cnblogs.com/TheRoadToTheGold/p/7655156.html
2017北京国庆刷题Day5 morning相关推荐
- 2017北京国庆刷题Day5 afternoon
期望得分:100+60+100=260 实际得分:0+60+40=100 设图中有m个环,每个环有si条边,有k条边不在环中 ans= (2^s1 -2)*( 2^s2 -2)* (2^s3 -2)- ...
- 2017北京国庆刷题Day2 afternoon
期望得分:100+100+50=250 实际得分:100+70+50=220 T1 最大值(max) Time Limit:1000ms Memory Limit:128MB 题目描述 LYK有一 ...
- LeetCode779 第K个语法符号 python刷题Day5
779.第K个语法符号 差一点今天就前功尽弃了,瘫在沙发上一时爽,一直瘫着废到老.想想昨天被一道评级为简单的题困住了.虽然我上学上的久,但我学的东西少啊.好了,开正题了,士可以一日不食而不能半日不学. ...
- 【套题】qbxt国庆刷题班D1
Day1 事实上D1的题目还是比较简单的= =然而D1T2爆炸了就十分尴尬--错失一波键盘 看题 T1 传送门 Description 现在你手里有一个计算器,上面显示了一个数\(S\),这个计算器十 ...
- 对于清北学堂2018国庆刷题班的学习总结
\(10.1\) 例题1: 最多因子数(Link) 给定一个区间\([L, R]\),要求求出在区间内拥有最大因子数的数. 定义\(F(X)\)为\(X\)的因子个数函数.首先我们要知道,对于任意一个 ...
- 2017 北京赛区 J题 Pangu and Stones 【区间DP】
题目链接:https://vjudge.net/problem/HihoCoder-1636: 题意:n堆石子,每次可以合并连续的 [ L~R ]堆石子,求最少的代价: /* 思路:区间DP;dp[i ...
- 国庆作业 刷题0929
国庆作业 刷题0929 使进度在90-95%截图上传 详情 第二本书 第一本书
- 【代码随想录】刷题笔记Day5
前言 竟然足足一星期没刷题了,上周毕设紧急赶了波工,就没什么动力,希望不会因此生疏了,组会过后刷新了焦虑值,又是新的一周,干巴爹 209. 长度最小的子数组 暴力解法:时间复杂度O(n2),两个for ...
- 2017.5.27测试 2. 刷题(P1167)
2 刷题 (c.pas/cpp/c) [题目背景] "好啊!一言为定!!",作为蒟蒻的GJY竟然约定和神犇来一场世纪大战. [题目描述] GJY在期末的时候跟神犇约定了一次战争,这 ...
最新文章
- 麻省理工学院揭秘男女配对的真相
- 2018年Github最受欢迎机器学习语言Python稳坐冠军,numpy、scipy是最受欢迎软件包...
- Zend Framework 的 PHP 编码标准
- 简述http请求中的同步和异步
- wxWidgets:wxCollapsiblePane类用法
- Python数据分析入门(四)
- c++:怎么将ctime时间转化为一个具体的秒数值_Linux下如何删除长时间不使用的旧文件?...
- android单个页面切换_Android基础之使用Fragment控制切换多个页面
- BurpSuite之HTTP brute暴力破解
- 练习题︱基于今日头条开源数据(二)——两款Apriori算法实践
- 如何用纯 CSS 创作 404 文字变形为 NON 文字的交互特效
- java读取zip文件损坏_java zip压缩文件损坏
- 51单片机流水灯现象2
- Linux中巧用zip命令压缩和解压缩文件
- 【读后感1】读《我是一只it小小鸟》有感
- canvas 文字颜色_Canvas 超全教程
- App Store拒绝原因
- Socket网络编程详解
- 56 行代码,带你爬取豆瓣影评
- 上海居住证及居住证积分常见问题(70个常见问题)