jzoj2865. 【集训队互测 2012】Attack(中等题)
虽然标算没有使用暴力,但是这道题的暴力算法还是值得记录一下。
我这种不会整体二分的蒟蒻肯定使用暴力算法。
首先我们可以根据题意得到一个$O(nmlog_2n)$的做法,显然会超时。可以用${nth\_element}$优化掉一个log。但是还是会tle(吸臭氧都不行)
这道题可以把所有点按照权值排序,设$id[i]$表示第i个节点现在在数组的哪一个位置。然后从小到大枚举权值,加入一个表的末尾。最后输出第k个即可。
实际上。我们把结点放进表末尾的顺序是按照权值从小到大。这样子就可以保证表是有序的。
这题还有修改操作。但是不难。直接修改对应位置即可
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
#include<bits/stdc++.h> using namespace std; #pragma GCC optimize("O3") #define N 60010 int n,m,ar[N],po[N],b[N]; struct no{ int x,y,z,id; bool operator <(const no &rhs)const{ return z<rhs.z; } }o[N]; int main(){ scanf("%d%d",&n,&m); for(int i=0;i<n;i++) scanf("%d%d%d",&o[i].x,&o[i].y,&o[i].z),o[i].id=i; sort(o,o+n); for(int i=0;i<n;i++) b[o[i].id]=i; while(m--){ char s[10]; scanf("%s",s); if(s[0]=='S'){ int c,d; scanf("%d%d",&c,&d); swap(o[b[c]].x,o[b[d]].x); swap(o[b[c]].y,o[b[d]].y); swap(o[b[c]].id,o[b[d]].id); swap(b[c],b[d]); } else{ int a,b,c,d,k,ta,tb,tc,td; scanf("%d%d%d%d%d",&ta,&tb,&tc,&td,&k); a=min(ta,tc);c=max(ta,tc); b=min(tb,td);d=max(tb,td); int ct=0; for(int i=0;i<n;i++) if(o[i].x<=c&&o[i].x>=a&&o[i].y<=d&&o[i].y>=b) ar[++ct]=o[i].z; if(ct<k)printf("It doesn't exist.\n"); else printf("%d\n",ar[k]); } } }
jzoj2867. 【集训队互测 2012】Contra (中等题)
可以使用dfs求状态,但是原来的dfs求出来的状态集,在更新最终答案的时候会延后一个单位所以不可以使用dfs。
先贴代码
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
#include<bits/stdc++.h> using namespace std; #pragma GCC optimize(3) int n,r,q,ct,nt[105][2],nm[105][105]; struct nn{ int x,y; bool operator <(const nn &rhs)const{ return x<rhs.x||(x==rhs.x&&y<rhs.y); } }a[105]; double s; map<nn,int>ma; struct no{ double a[105][105]; }bz,x; no mul(no x,no y){ no z; memset(z.a,0,sizeof(z.a)); for(int i=0;i<=ct;i++) for(int j=0;j<=ct;j++) for(int k=0;k<=ct;k++) if(x.a[i][k]>1e-15&&y.a[k][j]>1e-15)z.a[i][j]+=x.a[i][k]*y.a[k][j]; return z; } double mul(double p,int y){ memset(bz.a,0,sizeof(bz.a)); memset(x.a,0,sizeof(x.a)); for(int i=0;i<=100;i++) bz.a[i][i]=1; ct=0; for(int j=0;j<=r;j++) for(int i=min(j+1,q);i<=q;i++) nm[i][j]=ct++; for(int j=0;j<=r;j++) for(int i=min(j+1,q);i<=q;i++){ x.a[nm[i][j]][ct]+=p*min(j+1,r); x.a[nm[i][j]][nm[min(i+1,q)][min(j+1,r)]]+=p; if(i>1)x.a[nm[i][j]][nm[i-1][0]]+=(1-p); } x.a[ct][ct]=1; while(y){ if(y&1)bz=mul(bz,x); x=mul(x,x); y>>=1; } return bz.a[nm[q][0]][ct]; } int main(){ scanf("%d%d%d%lf",&n,&r,&q,&s); double a=0,b=1,ans=-2; while(a+1e-9<b){ double md=(a+b)*0.5; if(mul(md,n)>s)b=md-1e-9,ans=md; else a=md+1e-9; } if(ans!=-2)printf("%.6lf",ans); else printf("Impossible."); }//2 1 2 1
jzoj6011. 【NOIP2019模拟1.25A组】天天爱跑步 (难题)
注意到走的过程很像更相减损术,gcd值不变。所以可以把题目与gcd联系起来。
又注意到对于一个点$(x,y)$,只有1种方法使其变小。但是有2种方法让它变大。于是可以把这道题和树联系起来。
实际上,我们可以把$(x,y)->(x,x+y)$看作向右儿子移动,$(x,y)->(x+y,y)$看作向左儿子移动。则问题就转换成树上问题:有一个无限大的二叉树。每次移动产生1代价,给出若干个起点和终点。每个起点只能移动到一个终点。询问最小代价。我们可以在$log(n)$的时间内求出每一个点的深度。
由于二叉树太大。不可以直接建。于是可以考虑建一个虚树,把点放上去。然而建虚树的过程也太慢。要对节点排序,消耗巨量的时间。即使使用了$O(log_2 树高)$求lca,也会tle成70分。
定义这颗树上的“链的跳动”为:一个点向上跳,跳过的全是父亲的左儿子/右儿子边。则视为在链上跳动。一个点向上跳,跳到第一个$(x,y)$产生变迁(大小关系发生改变)的地方$(a,b)$,则视为跳到链顶。
考虑如下一种建树方法。可以把每个点向链顶连边。然后dfs整棵树计算答案。但是这种方法不能正确统计出答案。因为在新树上的lca不等于原树上的lca,原树的关系不可以维持
实际上,我们可以把每个点的子节点(一定在同一条链上)按照深度从小到大排序。然后深度小的累加深度大的答案即可。
最后就是统计答案的问题了。我们可以把起点的权值设为1,终点设为-1,把子树的1和-1尽量配对,剩下来的1向上合并就好了。
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
#include<bits/stdc++.h> using namespace std; #pragma GCC optimize("O3") #pragma G++ optimize("O3") #define O3 __attribute__((optimize("-O3"))) #define N 4000010 #define mo 4000007 typedef long long ll; struct no{ ll x,y; bool operator ==(const no &rhs)const{ return (x==rhs.x&&y==rhs.y); } }a[N],hs[N]; int operator !=(no x,no y){return !(x==y);} int hh(no v){return (v.x%mo*200407296+v.y%mo*998244353)%mo;} vector<int>vc[N][2]; int n;ll bz,ans,dep[N],sz[N]; O3 no is(no x){ int va=hh(x),bz=1; while(hs[va].x&&hs[va].y&&x!=hs[va])va=(va+1)%mo; if(!(hs[va].x||hs[va].y))hs[va]=x,dep[va]=x.x+x.y,bz=0; return (no){bz,va}; } O3 int cmp(int x,int y){return dep[x]>dep[y];} O3 void dfs(int x){ ll ct=0; for(int i=0;i<2;i++) if(vc[x][i].size()){ for(int j=0;j<vc[x][i].size();j++) dfs(vc[x][i][j]); sort(vc[x][i].begin(),vc[x][i].end(),cmp); int ls=vc[x][i][0]; ll vv=sz[ls],bz; if(i)bz=hs[x].x;else bz=hs[x].y; for(int j=1;j<vc[x][i].size();j++){ ans+=abs(vv)*((dep[ls]-dep[vc[x][i][j]])/bz); vv+=sz[vc[x][i][j]]; ls=vc[x][i][j]; } ct+=vv;ans+=abs(vv)*((dep[ls]-dep[x])/bz); } sz[x]+=ct; } O3 int main(){ scanf("%d",&n); for(int i=1;i<=n*2;i++){ scanf("%lld%lld",&a[i].x,&a[i].y); bz=__gcd(a[i].x,a[i].y); a[i].x/=bz;a[i].y/=bz; ll x=a[i].x,y=a[i].y,tp; if(is(a[i]).x)continue; while(x!=y){ no on=(no){x,y},nn; if(x>y)x%=y,tp=0; else y%=x,tp=1; if(!x||!y)x=y=1; nn=(no){x,y}; no xx=is(on),yy=is(nn); vc[yy.y][tp].push_back(xx.y); if(yy.x)break; } } for(int i=1;i<=n;i++){ sz[is(a[i]).y]++; sz[is(a[i+n]).y]--; } dfs(is((no){1,1}).y); printf("%lld",ans); }
jzoj3400. 【GDOI2014模拟】旅行
jzoj3738. 【NOI2014模拟7.11】理想城市(city)
jzoj6293 迷宫(中等题)
直接动态dp即可。注意常数
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
#include<bits/stdc++.h> using namespace std; #pragma GCC optimize("O2") #define mmin(x,y) x<y?x:y int n,m,q,v[10][200010],op,a,b,c,d,tx[4]={-1,0,1},ty[4]={0,1,0},di[10][200010],ok,gc; struct no{ int a[6][6]; }st[1000010],e[200010],bz,g; no mul(no x,no y){ no z; memset(z.a,63,sizeof(z.a)); for(int i=0;i<n;i++) for(int j=0;j<n;j++)if(x.a[i][j]<1e9) for(int k=0;k<n;k++)if(y.a[j][k]<1e9) z.a[i][k]=mmin(z.a[i][k],x.a[i][j]+y.a[j][k]); return z; } struct nn{ int x,y; }; void mod(int o,int l,int r,int x){ if(l==r){st[o]=e[l];return;} int md=(l+r)/2; if(x<=md)mod(o*2,l,md,x); else mod(o*2+1,md+1,r,x); st[o]=mul(st[o*2],st[o*2+1]); } void qu(int o,int l,int r,int x,int y){ if(r<x||y<l)return; if(x<=l&&r<=y){ if(!ok)ok=1,g=st[o]; else g=mul(g,st[o]); return; } int md=(l+r)/2; qu(o*2,l,md,x,y);qu(o*2+1,md+1,r,x,y); } void bd(int o,int l,int r){ if(l==r){ st[o]=e[l]; return; } int md=(l+r)/2; bd(o*2,l,md);bd(o*2+1,md+1,r); st[o]=mul(st[o*2],st[o*2+1]); } void get(int x){ queue<nn>q; for(int i=0;i<n;i++){ if(v[i][x])q.push((nn){i,x}); for(int j=x;j<x+2;j++) for(int k=0;k<n;k++) di[k][j]=1e9; di[i][x]=0; while(!q.empty()){ nn x=q.front();q.pop(); for(int i=0;i<3;i++){ int nx=x.x+tx[i],ny=x.y+ty[i]; if(nx<0||nx>=n||ny<0||ny>=m)continue; if(di[nx][ny]>di[x.x][x.y]+1&&v[nx][ny]){ di[nx][ny]=di[x.x][x.y]+1; q.push((nn){nx,ny}); } } } for(int j=0;j<n;j++) e[x].a[i][j]=di[j][x+1]; } if(gc)mod(1,0,m-2,x); } int main(){ //freopen("maze.in","r",stdin); //freopen("maze.out","w",stdout); scanf("%d%d%d",&n,&m,&q); for(int i=0;i<n;i++) for(int j=0;j<m;j++) scanf("%d",&v[i][j]); for(int i=0;i<n;i++)bz.a[i][i]=1; for(int i=0;i<m;i++)get(i); bd(1,0,m-2); gc=1; while(q--){ scanf("%d",&op); if(op==1){ scanf("%d%d",&a,&b); a--;b--;v[a][b]^=1; get(b);if(b>0)get(b-1); } else{ scanf("%d%d%d%d",&a,&b,&c,&d); a--;b--;c--;d--; if(b>d)printf("-1\n"); else if(b==d){ if(a>c)swap(a,c); int ok=1; for(int i=a;i<=c;i++) if(!v[i][b])ok=0; if(ok)printf("%d\n",c-a); else printf("-1\n"); } else{ ok=0; qu(1,0,m-2,b,d-1); if(g.a[a][c]<1e9)printf("%d\n",g.a[a][c]); else printf("-1\n"); } } } }