Day1
T1转圈游戏
很明显每进行n轮就一定会回到原来的位置,所以游戏只相当于进行了10k%n轮,所以会走到(x+10k%n)%n的位置。
写个快速幂也就没了。
1 #include<cstdio> 2 #include<algorithm> 3 int ksm(long long x,int y,int p){ 4 int res=1; 5 while(y){ 6 if(y&1)res=res*x%p; 7 x=x*x%p; 8 y>>=1; 9 } 10 return res; 11 } 12 int main(){ 13 int n,m,k,x; 14 scanf("%d %d %d %d",&n,&m,&k,&x); 15 printf("%d",(x+m*ksm(10,k,n)%n)%n); 16 return 0; 17 }
T2火柴排队
因为代价是差的平方级所以一定要让极差尽可能小(类似与基本不等式什么的?),那么很容易想到就是把两个序列按从小到大排序,一一对应。
那不就是求个逆序对吗=)-->移动两个序列的元素是等价的因此我们可以认定其中一个序列是有序的。
用树状数组或归并排序都可以。
1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 #define lowbit(x) x&-x 5 const int N=1e5+7,mod=99999997; 6 struct node{ 7 int wi,id; 8 }e[N],q[N]; 9 int n,pai[N],rank[N],to[N],tr[N]; 10 int read(){ 11 int ans=0,f=1;char c=getchar(); 12 while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();} 13 while(c>='0'&&c<='9'){ans=ans*10+c-48;c=getchar();} 14 return ans*f; 15 } 16 int ans=0; 17 bool cmp(node aa,node bb){return aa.wi<bb.wi;} 18 int sum(int x){ 19 long long ss=0; 20 for(;x<=n;x+=lowbit(x))ss=(ss+tr[x])%mod; 21 return ss; 22 } 23 void add(int x){ 24 for(;x;x-=lowbit(x))tr[x]++; 25 } 26 void ni(){ 27 for(int i=1;i<=n;i++){ 28 int ss=sum(rank[i]); 29 ans=(ans+ss)%mod; 30 add(rank[i]); 31 } 32 } 33 int main(){ 34 n=read(); 35 for(int i=1,a;i<=n;i++)a=read(),e[i]=(node){a,i}; 36 std::sort(e+1,e+1+n,cmp); 37 for(int i=1;i<=n;i++)pai[e[i].id]=i; 38 for(int i=1;i<=n;i++)to[pai[i]]=i; 39 for(int i=1,a;i<=n;i++)a=read(),q[i]=(node){a,i}; 40 std::sort(q+1,q+1+n,cmp); 41 for(int i=1;i<=n;i++)rank[q[i].id]=to[i]; 42 ni(); 43 printf("%d",ans); 44 return 0; 45 }
T3货车运输
既然是最大承重,当然就是先求一棵最大生成树辣><
然后就在倍增预处理时记一下每个节点每次向上跳2i时经过路径的最小值;
每次倍增求LCA时顺便取min就可以了。
1 #include<cstdio> 2 #include<cstring> 3 #include<queue> 4 #include<algorithm> 5 const int M=5e4+10,N=1e4+7,inf=0x3f3f3f3f; 6 struct node{ 7 int fr,to,w; 8 bool operator <(const node&p)const {return p.w>w;} 9 }; 10 struct no{int ne,to,w;}e[N*2]; 11 std::priority_queue<node>q; 12 int n,m,fa[N],tot=0,first[N],deep[N]; 13 int mni[N][20],gr[N][20]; 14 int min(int x,int y){return x>y?y:x;} 15 int read(){ 16 int ans=0,f=1;char c=getchar(); 17 while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();} 18 while(c>='0'&&c<='9'){ans=ans*10+c-48;c=getchar();} 19 return ans*f; 20 } 21 void ins(int u,int v,int w){ 22 e[++tot]=(no){first[u],v,w};first[u]=tot; 23 } 24 int getf(int x){return x==fa[x]?x:fa[x]=getf(fa[x]);} 25 void dfs(int x,int ff){ 26 for(int i=1;(1<<i)<=deep[x];i++){ 27 gr[x][i]=gr[gr[x][i-1]][i-1]; 28 mni[x][i]=min(mni[x][i-1],mni[gr[x][i-1]][i-1]); 29 } 30 for(int i=first[x];i;i=e[i].ne){ 31 int to=e[i].to; 32 if(to!=ff){ 33 deep[to]=deep[x]+1; 34 gr[to][0]=x;mni[to][0]=e[i].w; 35 dfs(to,x); 36 } 37 } 38 } 39 int lca(int x,int y){ 40 int mn=inf; 41 if(deep[x]<deep[y])std::swap(x,y); 42 int d=deep[x]-deep[y]; 43 for(int i=0;(1<<i)<=deep[x]&&i<=20;i++) 44 if(d&(1<<i)){ 45 mn=min(mn,mni[x][i]); 46 x=gr[x][i]; 47 } 48 if(x==y)return mn; 49 for(int i=20;i>=0;i--){ 50 if((1<<i)>deep[x]||gr[x][i]==gr[y][i])continue; 51 mn=min(mn,mni[x][i]);mn=min(mn,mni[y][i]); 52 x=gr[x][i];y=gr[y][i]; 53 } 54 if(!gr[x][0])return -1; 55 mn=min(mn,min(mni[x][0],mni[y][0])); 56 return mn; 57 } 58 int main(){ 59 n=read();m=read(); 60 for(int i=1,a,b,c;i<=m;i++){ 61 a=read();b=read();c=read(); 62 q.push((node){a,b,c}); 63 } 64 for(int i=1;i<=n;i++)fa[i]=i; 65 while(!q.empty()){ 66 node p=q.top();q.pop(); 67 int f1=getf(p.fr),f2=getf(p.to); 68 if(f1!=f2){ 69 ins(p.fr,p.to,p.w);ins(p.to,p.fr,p.w); 70 fa[f1]=f2; 71 } 72 } 73 dfs(1,0); 74 int qu=read(); 75 while(qu--){ 76 int x=read(),y=read(); 77 int mn=lca(x,y); 78 printf("%d ",mn); 79 } 80 return 0; 81 }
Day2
T1积木大赛
如果当前块比前一块高,说明需要多用hi[i]-hi[i-1]次。没了......
1 #include<cstdio> 2 #include<algorithm> 3 int main(){ 4 int n,x,last=0,ans=0; 5 scanf("%d",&n); 6 for(int i=1;i<=n;i++){ 7 scanf("%d",&x); 8 if(x>last)ans+=x-last; 9 last=x; 10 } 11 printf("%d",ans); 12 return 0; 13 }
T2花匠
求一下拐点数再+2,也解决了......
1 #include<cstdio> 2 #include<algorithm> 3 #include<cstring> 4 const int N=1e5+10; 5 int n,hi[N],tt; 6 int read(){ 7 int ans=0,f=1;char c=getchar(); 8 while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();} 9 while(c>='0'&&c<='9'){ans=ans*10+c-48;c=getchar();} 10 return ans*f; 11 } 12 int main(){ 13 n=read(); 14 for(int i=1;i<=n;i++)hi[i]=read(); 15 if(n==1)return printf("1"),0; 16 int t=2; 17 while(t<=n&&hi[t]==hi[t-1])t++; 18 if(hi[t]>hi[t-1])tt=1; 19 else tt=0; 20 int sum=1; 21 for(int i=t+1;i<=n;i++){ 22 if(hi[i]==hi[i-1])continue; 23 if(hi[i]>hi[i-1]&&!tt){ 24 sum++;tt^=1; 25 } 26 else if(hi[i]<hi[i-1]&&tt){ 27 sum++;tt^=1; 28 } 29 } 30 sum++; 31 printf("%d",sum); 32 return 0; 33 }
T3华容道
超超超超级恶心的预处理......
显然完成游戏是要先把白格子移到起点格子的四周,再用白格为起点格子铺路。
那么我们这里就需要求白格子铺路的代价,好在这题地图是确定的,因此我们可以先预处理出每个格子(当然是可移动的)四周的格子在不经过它本身的前提下互相到达的代价(bfs)。
最后跑一个带方向的SPFA-->预处理时也要记得记录是从哪个方向走到当前格子的。
最后还是看代码吧,写了一些注释......
1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 #include<queue> 5 #include<cmath> 6 #define mem(a,p) memset(a,p,sizeof(a)) 7 const int N=35,inf=0x3f3f3f3f; 8 int n,m,q,h1,t1,h2,t2,ex,ey,sx,sy,tx,ty; 9 int mp[N][N],cc[6][2]={{0,0},{0,1},{1,0},{-1,0},{0,-1}}; 10 int der[6]={0,4,3,2,1},step[N][N][6][6],dis[N][N][6]; 11 //der[k]存k的反方向,防止走回去导致死循 12 //dis[x][y][i]表示起始点从i方向走到(x,y)这个点的最小代价 13 bool ok[N][N]; 14 struct no{ 15 int x,y,st,k; 16 }q1[4000005],q2[4000005];//q1、q2分别是用于bfs和SPFA的队列 17 int min(int x,int y){return x>y?y:x;} 18 int read(){ 19 int ans=0,f=1;char c=getchar(); 20 while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();} 21 while(c>='0'&&c<='9'){ans=ans*10+c-48;c=getchar();} 22 return ans*f; 23 } 24 void pre(int x,int y){ 25 for(int i=1;i<=4;i++){ 26 if(!mp[x+cc[i][0]][y+cc[i][1]])continue; 27 for(int j=1;j<=4;j++){//mp[x][y]四个方向的格子(可移动的)两两相互到达所需代价 28 int ax=x+cc[i][0],ay=y+cc[i][1]; 29 if(i==j||step[x][y][i][j])continue; 30 int px=x+cc[j][0],py=y+cc[j][1]; 31 if(!mp[px][py])continue; 32 h1=1;t1=0; 33 mem(ok,0); 34 q1[++t1]=(no){ax,ay,0,i}; 35 ok[ax][ay]=1; 36 int ans=-1; 37 while(h1<=t1){ 38 no p=q1[h1];h1++; 39 if(p.x==px&&p.y==py){ans=p.st;break;} 40 for(int k=1;k<=4;k++){ 41 int bx=p.x+cc[k][0],by=p.y+cc[k][1]; 42 if(k==der[p.k]||!mp[bx][by]||ok[bx][by]||(bx==x&&by==y))continue;//bfs 43 q1[++t1]=(no){bx,by,p.st+1,k}; 44 ok[bx][by]=1; 45 } 46 } 47 step[x][y][i][j]=step[x][y][j][i]=ans; 48 } 49 } 50 } 51 void pre_white(){//预处理白格子走到起始格子四周的代价 52 h2=1;t2=0; 53 for(int i=1;i<=4;i++){ 54 if(!mp[sx+cc[i][0]][sy+cc[i][1]])continue; 55 mem(ok,0);h1=1;t1=0; 56 int px=sx+cc[i][0],py=sy+cc[i][1]; 57 q1[++t1]=(no){ex,ey,0,0};ok[ex][ey]=1; 58 int ans=inf; 59 while(h1<=t1){ 60 no p=q1[h1];h1++; 61 if(p.x==px&&p.y==py){ 62 ans=p.st; 63 if(ans<inf){ 64 q2[++t2]=(no){px,py,ans+1,i}; 65 dis[px][py][i]=ans+1; 66 }break; 67 } 68 for(int k=1;k<=4;k++){ 69 int bx=p.x+cc[k][0],by=p.y+cc[k][1]; 70 if(k==der[p.k]||!mp[bx][by]||ok[bx][by]||(bx==sx&&by==sy))continue; 71 q1[++t1]=(no){bx,by,p.st+1,k}; 72 ok[bx][by]=1; 73 } 74 } 75 } 76 } 77 void solve(){ 78 for(int i=1;i<=n;i++) 79 for(int j=1;j<=m;j++) 80 for(int k=1;k<=4;k++) 81 dis[i][j][k]=inf; 82 pre_white(); 83 int ans=inf; 84 while(h2<=t2){ 85 no p=q2[h2++]; 86 if(dis[p.x][p.y][p.k]!=p.st)continue; 87 if(p.x==tx&&p.y==ty){ 88 ans=min(ans,p.st); 89 continue; 90 } 91 for(int k=1;k<=4;k++){ 92 int bx=p.x+cc[k][0],by=p.y+cc[k][1]; 93 if(k==der[p.k]||!mp[bx][by])continue; 94 int wi=step[p.x][p.y][der[p.k]][k]; 95 if(wi<=0)continue;//说明此格子走不过来 96 if(dis[bx][by][k]>dis[p.x][p.y][p.k]+wi+1){//带方向变量的SPFA 97 dis[bx][by][k]=dis[p.x][p.y][p.k]+wi+1; 98 q2[++t2]=(no){bx,by,dis[bx][by][k],k}; 99 } 100 } 101 } 102 if(ans>=inf||ans<=0)printf("-1 "); 103 else printf("%d ",ans); 104 } 105 int main(){ 106 n=read();m=read();q=read(); 107 for(int i=1;i<=n;i++) 108 for(int j=1;j<=m;j++) 109 mp[i][j]=read(); 110 for(int i=1;i<=n;i++) 111 for(int j=1;j<=m;j++) 112 if(mp[i][j])pre(i,j); 113 while(q--){ 114 ex=read();ey=read();sx=read();sy=read();tx=read();ty=read(); 115 if(sx==tx&&sy==ty)printf("0 ");//记得特判...... 116 else solve(); 117 } 118 return 0; 119 }