4-22ACM训练题解(ZOJ Monthly Jan 2019)
A little sub and pascal's triangle ZOJ - 4081 by ltr
打表题,打表发现前2^n和后2^n是二倍关系,递归即可。
1 #include<iostream> 2 #include<cstdlib> 3 #include<cstdio> 4 #include<cstring> 5 #include<algorithm> 6 #include<cmath> 7 using namespace std; 8 int T; 9 long long K,xp[2000]; 10 int cnt[200]; 11 long long C[20][20]; 12 long long get(long long x) 13 { 14 if(x==1) return 1; 15 int bj=0; 16 for(int i=0;i<=64;i++) 17 { 18 if(xp[i]==x) 19 { 20 return xp[i]; 21 } 22 if(xp[i]<=x&&xp[i+1]>x) 23 { 24 bj=i; 25 break; 26 } 27 } 28 long long t=x-xp[bj]; 29 if(t>xp[bj-1]) 30 { 31 return 2ll*get(x-xp[bj-1]); 32 } 33 else 34 { 35 return 2ll*get(x-xp[bj]); 36 } 37 } 38 int main() 39 { 40 scanf("%d",&T); 41 xp[0]=1; 42 for(int i=1;i<=64;i++) xp[i]=xp[i-1]*2ll; 43 while(T--) 44 { 45 scanf("%lld",&K); 46 printf("%lld\n",get(K)); 47 } 48 return 0; 49 }
B-Little Sub and his Geometry Problem ZOJ - 4082 by wxh
当x递增的时候,y是递减的,所以只需要单调用优先队列的维护值,然后计算即可。
E - Little Sub and Mr.Potato's Math Problem ZOJ - 4085 by myl
数位DP思想,思维难度较大
有一点显而易见,N>M,且随着N增加,M所在位置k也会增加
首先可以计算比K小的数中,按字典序还比K小的数。
当结果k小于M-1,则无解。否则,继续寻找比K大的,按字典序寻找即可
1 #include<cstdio> 2 long long a,b,c,d,e,f,g,h,n,i; 3 char w[100]; 4 int main() 5 { 6 scanf("%lld",&n); 7 for(h=1;h<=n;h++) 8 { 9 scanf("%s%lld",w,&a); 10 b=0; 11 c=0; 12 d=0; 13 e=0; 14 f=0; 15 while(('0'<=w[d])&&(w[d]<='9')) 16 { 17 b=b*10+w[d]-'0'; 18 f=f+w[d]-'0'; 19 if(d==0) b--; 20 c=c+b+1; 21 d++; 22 e=e*10+9; 23 } 24 if((c>a)||((c!=a)&&(f==1))) printf("0"); 25 else 26 { 27 if(c==a) printf("%s",w); 28 if(c<a) 29 { 30 d=0; 31 while(c<a) 32 { 33 b=b*10; 34 c=c+b; 35 d++; 36 e=e*10+9; 37 } 38 e=e/10+1; 39 c=c-b+1; 40 a=a-c; 41 printf("%lld",e+a); 42 } 43 } 44 if(h!=n) printf("\n"); 45 } 46 return 0; 47 }
G little sub and tree ZOJ - 4087 by ltr
在纸上瞎划拉发现的……
首先,我们可以发现特殊点选度数为1的点一定不劣。
我们假设他是一棵有根树,根的入度为1,且根为特殊点那么当我们dfs到某个节点时,我们可以分情况讨论:
1.该节点有至少两个儿子,且至少有一个儿子向下走是一条链。那么除了某条向下为链的儿子以外其余的儿子的子树里面必须有特殊点。
2.该节点有儿子,且没有儿子向下为链,那么所有儿子的子树里面都必须有特殊点。
3.该节点为叶节点,那么他一定是特殊点。
之后我们还要判断根节点是否为特殊点,判断依据就是根节点第一个有多个儿子的后代的儿子的子树的情况,如果该节点有儿子向下为链,则根节点一定是特殊点。
1 #include<iostream> 2 #include<cstdlib> 3 #include<cstdio> 4 #include<cstring> 5 #include<algorithm> 6 #include<cmath> 7 #include<queue> 8 #include<map> 9 #include<ctime> 10 #define N 100005 11 using namespace std; 12 int T,n; 13 struct ro{ 14 int to,next; 15 }road[N*2]; 16 int zz,a[N]; 17 void build(int x,int y) 18 { 19 zz++; 20 road[zz].to=y; 21 road[zz].next=a[x]; 22 a[x]=zz; 23 } 24 int fa[N],rd[N],root,cnt[N],cnt2[N],cnt3[N]; 25 int zz1,ans[N]; 26 void dfs1(int x) 27 { 28 29 if(rd[x]==1) cnt[x]=1,cnt2[x]=1; 30 for(int i=a[x];i;i=road[i].next) 31 { 32 33 int y=road[i].to; 34 if(y==fa[x])continue; 35 fa[y]=x; 36 dfs1(y); 37 cnt3[x]++; 38 cnt[x]+=cnt[y]; 39 if(cnt[y]==1) cnt2[x]++; 40 } 41 } 42 void dfs2(int x,bool yx) 43 { 44 if(yx) 45 { 46 if(cnt3[x]!=1) 47 { 48 if(cnt2[x]) 49 { 50 zz1++,ans[zz1]=root; 51 } 52 yx=0; 53 } 54 } 55 bool yx2=1; 56 if(cnt2[x]==1&&cnt3[x]==1) yx2=0; 57 for(int i=a[x];i;i=road[i].next) 58 { 59 int y=road[i].to; 60 if(y==fa[x])continue; 61 if(cnt[y]==1&&yx2) 62 { 63 yx2=0; 64 continue; 65 } 66 dfs2(y,yx); 67 } 68 if(rd[x]==1&&x!=root) 69 { 70 zz1++; 71 ans[zz1]=x; 72 } 73 } 74 int main() 75 { 76 scanf("%d",&T); 77 while(T--) 78 { 79 zz=0; 80 scanf("%d",&n); 81 memset(rd,0,sizeof(int)*(n+4)); 82 memset(a,0,sizeof(int)*(n+4)); 83 memset(fa,0,sizeof(int)*(n+4)); 84 memset(cnt,0,sizeof(int)*(n+4)); 85 memset(cnt2,0,sizeof(int)*(n+4)); 86 memset(cnt3,0,sizeof(int)*(n+4)); 87 88 for(int i=1;i<n;i++) 89 { 90 int x,y; 91 scanf("%d%d",&x,&y); 92 build(x,y); 93 build(y,x); 94 rd[x]++;rd[y]++; 95 } 96 for(int i=1;i<=n;i++) 97 { 98 if(rd[i]==1) 99 { 100 root=i; 101 break; 102 } 103 } 104 zz1=0; 105 dfs1(root); 106 dfs2(root,1); 107 if(zz1==0) 108 { 109 zz1=1,ans[1]=root; 110 } 111 printf("%d\n",zz1); 112 for(int i=1;i<zz1;i++) printf("%d ",ans[i]); 113 printf("%d\n",ans[zz1]); 114 } 115 return 0; 116 }
I Little Sub and Isomorphism Sequences ZOJ - 4089 by ltr
一个很重要的结论是最长的两个同构子串他们一定有重合部分,因为两个重构子串算上他们之间的未重合部分一定仍然重构。
接着,我们会发现一个更为美妙的性质。就是最长子串的长度一定等于某个数字最后一次出现的下标减去第一次出现的下标,也就是他们之间的公共部分加上一个端点构成的两个子串,而且这样一定不劣。(具体证明不太会,但是在纸上划拉记下就能感觉到没问题)。
那么就很简单了,我们用把相同数字的下标放到一个set里,每次取出来头尾元素就可以了。
(由于我太菜不会set,用优先队列强行模拟的……)
1 #include<iostream> 2 #include<cstdlib> 3 #include<cstdio> 4 #include<cstring> 5 #include<algorithm> 6 #include<cmath> 7 #include<queue> 8 #include<map> 9 #define N 200005 10 using namespace std; 11 int T,n,m,A[N]; 12 priority_queue<int> q1[N][2],q3[2]; 13 priority_queue<int,vector<int>,greater<int > > q2[N][2]; 14 map<int,int> ma; 15 int zz,B[N],f[N][10]; 16 int main() 17 { 18 scanf("%d",&T); 19 while(T--) 20 { 21 scanf("%d%d",&n,&m); 22 ma.clear(); 23 zz=0; 24 for(int i=1;i<=n;i++) 25 { 26 scanf("%d",&A[i]); 27 if(!ma.count(A[i])) 28 { 29 ma[A[i]]=1; 30 zz++; 31 B[zz]=A[i]; 32 } 33 } 34 for(int i=1;i<=m;i++) 35 { 36 scanf("%d",&f[i][0]); 37 if(f[i][0]==1) 38 { 39 scanf("%d%d",&f[i][1],&f[i][2]); 40 if(!ma.count(f[i][2])) 41 { 42 ma[f[i][2]]=1; 43 zz++; 44 B[zz]=f[i][2]; 45 } 46 } 47 } 48 sort(B+1,B+zz+1); 49 for(int i=1;i<=zz;i++) ma[B[i]]=i; 50 for(int i=1;i<=n;i++) A[i]=ma[A[i]]; 51 for(int i=1;i<=m;i++) 52 { 53 if(f[i][0]==1) f[i][2]=ma[f[i][2]]; 54 } 55 int ans=-1; 56 for(int i=1;i<=n;i++) 57 { 58 q1[A[i]][0].push(i); 59 q2[A[i]][0].push(i); 60 } 61 for(int i=1;i<=zz;i++) 62 { 63 if(q1[i][0].empty()) continue; 64 q3[0].push(q1[i][0].top()-q2[i][0].top()); 65 } 66 for(int i=1;i<=m;i++) 67 { 68 if(f[i][0]==1) 69 { 70 int x=f[i][1],y=f[i][2]; 71 72 q1[A[x]][1].push(x); 73 q2[A[x]][1].push(x); 74 q3[1].push(q1[A[x]][0].top()-q2[A[x]][0].top()); 75 while(!q1[A[x]][0].empty()&&!q1[A[x]][1].empty()&&q1[A[x]][0].top()==q1[A[x]][1].top()) q1[A[x]][0].pop(),q1[A[x]][1].pop(); 76 while(!q2[A[x]][0].empty()&&!q2[A[x]][1].empty()&&q2[A[x]][0].top()==q2[A[x]][1].top()) q2[A[x]][0].pop(),q2[A[x]][1].pop(); 77 if(!q1[A[x]][0].empty()&&!q2[A[x]][0].empty())q3[0].push(q1[A[x]][0].top()-q2[A[x]][0].top()); 78 79 80 if(!q1[y][0].empty()&&!q2[y][0].empty())q3[1].push(q1[y][0].top()-q2[y][0].top()); 81 q1[y][0].push(x); 82 q2[y][0].push(x); 83 while(!q1[y][0].empty()&&!q1[y][1].empty()&&q1[y][0].top()==q1[y][1].top()) q1[y][0].pop(),q1[y][1].pop(); 84 while(!q2[y][0].empty()&&!q2[y][1].empty()&&q2[y][0].top()==q2[y][1].top()) q2[y][0].pop(),q2[y][1].pop(); 85 if(!q1[y][0].empty()&&!q2[y][0].empty())q3[0].push(q1[y][0].top()-q2[y][0].top()); 86 A[x]=y; 87 } 88 else 89 { 90 while(!q3[0].empty()&&!q3[1].empty()&&q3[0].top()==q3[1].top()) q3[0].pop(),q3[1].pop(); 91 if(q3[0].empty()||q3[0].top()==0) printf("-1\n"); 92 else printf("%d\n",q3[0].top()); 93 } 94 } 95 for(int i=1;i<=zz;i++) 96 { 97 while(!q1[i][0].empty()) q1[i][0].pop(); 98 while(!q1[i][1].empty()) q1[i][1].pop(); 99 100 while(!q2[i][0].empty()) q2[i][0].pop(); 101 while(!q2[i][1].empty()) q2[i][1].pop(); 102 } 103 while(!q3[0].empty()) q3[0].pop(); 104 while(!q3[1].empty()) q3[1].pop(); 105 } 106 107 return 0; 108 }