1001 Travel with candy
1002 The sum of gcd
学了莫队补的。基本还是别人的方法。
先预处理出每个点左右的gcd区间。最多log(a[i])个。
然后套莫队转移。
1 # include <iostream> 2 # include <cstdio> 3 # include <vector> 4 # include <algorithm> 5 # include <cmath> 6 using namespace std; 7 typedef long long LL; 8 const int maxn=10000+10; 9 int n,Q,block,a[maxn]; 10 LL ans[maxn]; 11 12 struct node 13 { 14 int no,l,r,gcd; 15 } query[maxn]; 16 vector <node> Lgcd[maxn],Rgcd[maxn]; 17 18 bool cmp(node a,node b) 19 { 20 if(a.l/block!=b.l/block) return a.l/block<b.l/block; 21 return a.r<b.r; 22 } 23 24 int gcd(int a,int b) 25 { 26 return a%b?gcd(b,a%b):b; 27 } 28 29 void Init(void) 30 { 31 scanf("%d",&n); 32 for(int i=1;i<=n;i++) 33 { 34 scanf("%d",a+i); 35 Lgcd[i].clear(); 36 Rgcd[i].clear(); 37 } 38 scanf("%d",&Q); 39 for(int i=1;i<=Q;i++) 40 { 41 scanf("%d%d",&query[i].l,&query[i].r); 42 query[i].no=i; 43 } 44 block=sqrt(n); 45 sort(query+1,query+1+Q,cmp); 46 return; 47 } 48 49 void PrePro(void) 50 { 51 for(int i=1;i<=n;i++) 52 { 53 int pos=i,tem_gcd=a[i]; 54 for(int j=0;j<Lgcd[i-1].size();j++) 55 { 56 node tem=Lgcd[i-1][j]; 57 int t=gcd(tem.gcd,tem_gcd); 58 if(t!=tem_gcd)Lgcd[i].push_back(node{0,pos,0,tem_gcd}); 59 pos=tem.l,tem_gcd=t; 60 } 61 Lgcd[i].push_back(node{0,pos,0,tem_gcd}); 62 } 63 Rgcd[n+1].clear(); 64 for(int i=n;i>=1;i--) 65 { 66 int pos=i,tem_gcd=a[i]; 67 for(int j=0;j<Rgcd[i+1].size();j++) 68 { 69 node tem=Rgcd[i+1][j]; 70 int t=gcd(tem.gcd,tem_gcd); 71 if(t!=tem_gcd)Rgcd[i].push_back(node{0,0,pos,tem_gcd}); 72 pos=tem.r,tem_gcd=t; 73 } 74 Rgcd[i].push_back(node{0,0,pos,tem_gcd}); 75 } 76 return; 77 } 78 79 void Solve(void) 80 { 81 LL res=0; 82 int l=1,r=0; 83 for(int i=1;i<=Q;i++) 84 { 85 while(r<query[i].r) 86 { 87 int pos=++r; 88 for(int j=0;j<Lgcd[r].size();j++) 89 { 90 node tem=Lgcd[r][j]; 91 if(tem.l>=l){res+=(LL)(pos-tem.l+1)*(LL)tem.gcd; pos=tem.l-1;} 92 else {res+=(LL)(pos-l+1)*(LL)tem.gcd; break;} 93 } 94 } 95 for(;r>query[i].r;r--) 96 { 97 int pos=r; 98 for(int j=0;j<Lgcd[r].size();j++) 99 { 100 node tem=Lgcd[r][j]; 101 if(tem.l>=l){res-=(LL)(pos-tem.l+1)*(LL)tem.gcd; pos=tem.l-1;} 102 else {res-=(LL)(pos-l+1)*(LL)tem.gcd; break;} 103 } 104 } 105 while(l>query[i].l) 106 { 107 int pos=--l; 108 for(int j=0;j<Rgcd[l].size();j++) 109 { 110 node tem=Rgcd[l][j]; 111 if(tem.r<=r){res+=(LL)(tem.r-pos+1)*(LL)tem.gcd; pos=tem.r+1;} 112 else {res+=(LL)(r-pos+1)*(LL)tem.gcd; break;} 113 } 114 } 115 for(;l<query[i].l;l++) 116 { 117 int pos=l; 118 for(int j=0;j<Rgcd[l].size();j++) 119 { 120 node tem=Rgcd[l][j]; 121 if(tem.r<=r){res-=(LL)(tem.r-pos+1)*(LL)tem.gcd; pos=tem.r+1;} 122 else {res-=(LL)(r-pos+1)*(LL)tem.gcd; break;} 123 } 124 } 125 ans[query[i].no]=res; 126 } 127 return; 128 } 129 130 int main(void) 131 { 132 int T; cin>>T; 133 while(T--) 134 { 135 Init(); 136 PrePro(); 137 Solve(); 138 for(int i=1;i<=Q;i++) printf("%I64d ",ans[i]); 139 } 140 return 0; 141 }
1003 GCD?LCM!
1004 Yu-Gi-Oh!
1005 Danganronpa
1006 The path
从1一开始往大的数BFS。搜到没路为止。
dis就是以1间隔递增。
再从n反向搜回来。一样操作。
因为保证有解。所以两遍一定搜完所有点。
对于所有u到v的边。如果dis[u]>dis[v]那么这条边肯定不走。置为最大值n即可。
否则把边置为dis[v]-dis[u]就符合要求了。
1 # include <iostream> 2 # include <cstdio> 3 # include <cstring> 4 using namespace std; 5 # define maxn 100100 6 int cnt,headlist[maxn],dis[maxn]; 7 8 struct node 9 { 10 int to,pre,val; 11 } edge[maxn]; 12 13 void add(int from,int to) 14 { 15 cnt++; 16 edge[cnt].pre=headlist[from]; 17 edge[cnt].to=to; 18 headlist[from]=cnt; 19 } 20 21 int main(void) 22 { 23 int T; cin>>T; 24 while(T--) 25 { 26 cnt=0; 27 memset(headlist,0,sizeof(headlist)); 28 memset(dis,-1,sizeof(dis)); 29 int n,m; scanf("%d%d",&n,&m); 30 for(int i=1;i<=m;i++) 31 { 32 int u,v; 33 scanf("%d%d",&u,&v); 34 add(u,v); 35 } 36 dis[1]=0; 37 int l=1,r=n,pos; 38 for(int i=1;i<=n;i++) 39 { 40 if(dis[l]>=0) pos=l++; 41 else pos=r--; 42 dis[pos]=i; 43 for(int j=headlist[pos];j;j=edge[j].pre) 44 { 45 int to=edge[j].to; 46 if(dis[to]>=0) continue; 47 dis[to]=0; 48 } 49 } 50 for(int i=1;i<=n;i++) 51 for(int j=headlist[i];j;j=edge[j].pre) 52 edge[j].val=dis[edge[j].to]>dis[i]?dis[edge[j].to]-dis[i]:n; 53 for(int i=1;i<=m;i++) printf("%d ",edge[i].val); 54 } 55 return 0; 56 }
1007 Cover
只要不是那么暴力的暴力应该就- -。
1 # include <iostream> 2 # include <cstdio> 3 using namespace std; 4 int map[101][101],ans[501]; 5 6 struct node 7 { 8 int type,num,col,used; 9 } op[501]; 10 11 int main(void) 12 { 13 int T; cin>>T; 14 while(T--) 15 { 16 int n,m; scanf("%d%d",&n,&m); 17 for(int t=0;t<2;t++) 18 for(int i=1;i<=n;i++) 19 for(int j=1;j<=n;j++) 20 scanf("%d",&map[i][j]); 21 for(int i=1;i<=m;i++) 22 { 23 char s[5]; 24 scanf("%s",s); 25 if(s[0]=='L') op[i].type=0; 26 else op[i].type=1; 27 scanf("%d%d",&op[i].num,&op[i].col); 28 op[i].used=0; 29 } 30 int cnt=m; 31 while(cnt) 32 { 33 for(int i=1;i<=m;i++) 34 { 35 if(!op[i].used) 36 { 37 int ok=1; 38 if(op[i].type) 39 { 40 int x=op[i].num,c=op[i].col; 41 for(int j=1;j<=n;j++) 42 if(map[x][j]&&map[x][j]!=c) 43 {ok=0;break;} 44 if(ok) 45 { 46 op[i].used=1; 47 ans[cnt--]=i; 48 for(int j=1;j<=n;j++) map[x][j]=0; 49 for(int j=1;j<=m;j++) 50 if(op[j].type&&!op[j].used&&op[j].num==x) 51 { 52 op[j].used=1; 53 ans[cnt--]=j; 54 } 55 } 56 } 57 else 58 { 59 int x=op[i].num,c=op[i].col; 60 for(int j=1;j<=n;j++) 61 if(map[j][x]&&map[j][x]!=c) 62 {ok=0;break;} 63 if(ok) 64 { 65 op[i].used=1; 66 ans[cnt--]=i; 67 for(int j=1;j<=n;j++) map[j][x]=0; 68 for(int j=1;j<=m;j++) 69 if(!op[j].type&&!op[j].used&&op[j].num==x) 70 { 71 op[j].used=1; 72 ans[cnt--]=j; 73 } 74 } 75 } 76 } 77 } 78 } 79 for(int i=1;i<=m;i++) printf("%d ",ans[i]); 80 puts(""); 81 } 82 return 0; 83 }
1008 Clock
枚举所有时刻指针夹角即可。
1 # include <iostream> 2 # include <cstdio> 3 # include <algorithm> 4 using namespace std; 5 6 struct node 7 { 8 int h,m,s,a1,a2,b1,b2,c1,c2; 9 } Time[44000]; 10 11 void ans_print(int h,int m,int s) 12 { 13 int index=3600*h+60*m+s; 14 if(Time[index].a2==1) printf("%d ",Time[index].a1); 15 else printf("%d/%d ",Time[index].a1,Time[index].a2); 16 if(Time[index].b2==1) printf("%d ",Time[index].b1); 17 else printf("%d/%d ",Time[index].b1,Time[index].b2); 18 if(Time[index].c2==1) printf("%d ",Time[index].c1); 19 else printf("%d/%d ",Time[index].c1,Time[index].c2); 20 printf(" "); 21 return; 22 } 23 24 void Init(void) 25 { 26 for(int h=0;h<12;h++) 27 { 28 for(int m=0;m<60;m++) 29 { 30 for(int s=0;s<60;s++) 31 { 32 int index=3600*h+60*m+s; 33 34 int as=s*720; 35 int am=720*m+12*s; 36 int ah=3600*h+60*m+s; 37 38 int a1=max(ah,am)-min(ah,am); 39 if(a1>21600) a1=43200-a1; 40 int a2=120; 41 while(a1%2==0&&a2%2==0){a1/=2;a2/=2;} 42 while(a1%3==0&&a2%3==0){a1/=3;a2/=3;} 43 while(a1%5==0&&a2%5==0){a1/=5;a2/=5;} 44 45 int b1=max(ah,as)-min(ah,as); 46 if(b1>21600) b1=43200-b1; 47 int b2=120; 48 while(b1%2==0&&b2%2==0){b1/=2;b2/=2;} 49 while(b1%3==0&&b2%3==0){b1/=3;b2/=3;} 50 while(b1%5==0&&b2%5==0){b1/=5;b2/=5;} 51 52 int c1=max(as,am)-min(as,am); 53 if(c1>21600) c1=43200-c1; 54 int c2=120; 55 while(c1%2==0&&c2%2==0){c1/=2;c2/=2;} 56 while(c1%3==0&&c2%3==0){c1/=3;c2/=3;} 57 while(c1%5==0&&c2%5==0){c1/=5;c2/=5;} 58 59 Time[index].h=h; 60 Time[index].m=m; 61 Time[index].s=s; 62 Time[index].a1=a1; 63 Time[index].a2=a2; 64 Time[index].b1=b1; 65 Time[index].b2=b2; 66 Time[index].c1=c1; 67 Time[index].c2=c2; 68 } 69 } 70 } 71 return; 72 } 73 74 int main(void) 75 { 76 Init(); 77 int T ;cin>>T; 78 while(T--) 79 { 80 int h,m,s; 81 scanf("%d",&h); 82 if(h>=12) h-=12; 83 getchar(); 84 scanf("%d",&m); 85 getchar(); 86 scanf("%d",&s); 87 ans_print(h,m,s); 88 } 89 return 0; 90 }
1009 Geometer's Sketchpad
1010 Zero Escape
dp题。
定义状态:dp[i][j]为前i个人中选至少一个人(取的人数小于等于i即可)。使得dr=j的情况数。
转移:dp[i][j]=dp[i-1][(j-num+8)%9+1]+dp[i-1][j],dp[i][num]++。
i-1个人(j-num+8)%9+1的情况加上第i个num正好凑成j。再加上不选择第i个人的情况。最后再考虑只取第i个人的情况。
对9取模后。如果sum等于A+B的话。说明可以组合成两道门都走的情况。
但是这里注意前面dp定义的是至少选一个人的情况。如果B=sum。就存在全部走B不走A的情况。
所以答案是dp[n][A]+(B==sum)或者dp[n][B]+(A==sum)也一样。
如果sum不等于A+B。那么最多选择一扇门走完。
判断能否走A。能否走B。即可。
1 # include <iostream> 2 # include <cstdio> 3 # include <algorithm> 4 using namespace std; 5 typedef long long LL; 6 const int maxn=101000; 7 const LL mod=258280327; 8 LL dp[maxn][10]; 9 10 int main(void) 11 { 12 int T; cin>>T; 13 while(T--) 14 { 15 int n,A,B,num; 16 scanf("%d%d%d",&n,&A,&B); 17 int sum=0; 18 for(int i=1;i<=n;i++) 19 { 20 scanf("%d",&num); 21 sum+=num; 22 for(int j=1;j<=9;j++) dp[i][j]=(dp[i-1][(j-num+8)%9+1]+dp[i-1][j])%mod; 23 dp[i][num]=(dp[i][num]+(LL)1)%mod; 24 } 25 sum=(sum-1)%9+1; 26 if(sum==(A+B-1)%9+1) printf("%I64d ",(dp[n][A]+(LL)(B==sum))%mod); 27 else printf("%d ",(sum==A)+(sum==B)); 28 } 29 return 0; 30 }
1011 tree