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 }
View Code

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 } 
View Code

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 }
View Code

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 }
View Code
posted @ 2020-04-27 21:53  Hzoi_joker  阅读(149)  评论(0编辑  收藏  举报