Codeforces Global Round 1 做题记录

A.

题解:快速幂

 1 #include<bits/stdc++.h>
 2 #define ll long long
 3 #define maxn 100005
 4 using namespace std;
 5 const ll mod=2;
 6 ll b,k;
 7 ll a[maxn];
 8 ll fastpow(ll a,ll p)
 9 {
10     ll ans=1;
11     while(p)
12     {
13         if(p&1)ans=ans*a%mod;
14         a=a*a%mod;p>>=1;
15     }
16     return ans;
17 }
18 int main()
19 {
20     scanf("%I64d%I64d",&b,&k);
21     for(int i=1;i<=k;++i)scanf("%I64d",&a[i]);
22     ll n=0;
23     for(int i=1;i<=k;++i)n=(n+a[i]*fastpow(b,k-i)%mod)%mod;
24     if(n)puts("odd");
25     else puts("even");
26 }
View Code

 

B.

题解:考虑两两相邻点之间的距离,贪心取最小的k-1个

 1 #include<bits/stdc++.h>
 2 #define maxn 100005
 3 using namespace std;
 4 int n,m,k;
 5 int a[maxn];
 6 priority_queue<int,vector<int>,greater<int> >q;
 7 int main()
 8 {
 9     scanf("%d%d%d",&n,&m,&k);
10     int ans=n;
11     for(int i=1;i<=n;++i)scanf("%d",&a[i]);
12     k=n-k;
13     for(int i=1;i<n;++i)q.push(a[i+1]-a[i]-1);
14     while(k--)
15     {
16         int t=q.top();
17         q.pop();
18         ans+=t;
19     }
20     printf("%d\n",ans);
21     return 0;
22 }
View Code

 

C.

题解:找规律,除了2^k-1以外其他情况ans=2^p-1(其中p为满足ans>a的最小的数),2^k-1的情况打表就行

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 int q;
 4 int vis[]={0,0,1,1,5,1,21,1,85,73,341,89,1365,1,5461,4681,21845,1,87381,1,349525,299593,1398101,178481,5592405,1082401};
 5 int main()
 6 {
 7     scanf("%d",&q);
 8     while(q--)
 9     {
10         int a;
11         scanf("%d",&a);
12         int p=1;
13         while(((1<<p)-1)<a)p++;
14         if(a==((1<<p)-1))
15         {
16             if(!vis[p])
17             {
18                 int ans=0;
19                 for(int b=1;b<a;++b)ans=max(ans,__gcd(a^b,a&b));
20                 vis[p]=ans;
21                 printf("%d\n",ans);
22             }
23             else printf("%d\n",vis[p]);
24         }
25         else printf("%d\n",(1<<p)-1);
26     }
27     return 0;
28 }
View Code

 

D.

题解:考虑3个三元组[ i-1 ,i ,i+1 ]可以被拆成[ i-1, i-1, i-1 ] , [ i , i , i ] , [ i+1, i+1, i+1 ],所以每个状态中这样的三元组不会超过2个

然后dp(i,j,k)表示有j个[ i-1 ,i ,i+1 ] , k个[ i , i+1 , i+2 ],转移每次枚举一个 l ,表示dp(i+1,k,l),其中多l个[ i+1 , i+2, i+3 ]

那相同的三元组怎么处理?( num(i) - j -k -l )/3 个,直接加上就好了

 1 #include<bits/stdc++.h>
 2 #define inf 1000000000
 3 #define maxn 1000005
 4 using namespace std;
 5 int n,m;
 6 int has[maxn];
 7 int dp[maxn][3][3];
 8 int main()
 9 {
10     scanf("%d%d",&n,&m);
11     for(int x,i=1;i<=n;++i)
12     {
13         scanf("%d",&x);
14         has[x]++;
15     }
16     for(int i=0;i<=m;++i)
17     {
18         for(int j=0;j<=2;++j)
19         {
20             for(int k=0;k<=2;++k)dp[i][j][k]=-inf;
21         }
22     }
23     dp[0][0][0]=0;
24     for(int i=0;i<m;++i)
25     {
26         for(int j=0;j<=min(has[i],2);++j)
27         {
28             for(int k=0;k<=min(has[i+1],2);++k)
29             {
30                 for(int l=0;l<=min(has[i+2],2);++l)if(has[i+1]>=j+k+l)
31                 {
32                     dp[i+1][k][l]=max(dp[i+1][k][l],dp[i][j][k]+l+(has[i+1]-j-k-l)/3);
33                 }
34             }
35         }
36     }
37     printf("%d\n",dp[m][0][0]);
38     return 0;
39 }
View Code

 

E.

题解:原题,以前有一道前缀和类似的结论

考虑每次操作,本质上是在差分数组中交换两个数的位置

我们只需要判断差分数组是否同构以及原数组首尾是否相同就行了

 1 #include<bits/stdc++.h>
 2 #define ll long long
 3 #define maxn 100005
 4 using namespace std;
 5 int n;
 6 ll c[maxn],t[maxn],x[maxn],y[maxn]; 
 7 int main()
 8 {
 9     scanf("%d",&n);
10     for(int i=1;i<=n;++i)scanf("%I64d",&c[i]);
11     for(int i=1;i<=n;++i)scanf("%I64d",&t[i]);
12     if(c[1]!=t[1]||c[n]!=t[n])
13     {
14         puts("No");
15         return 0;
16     }
17     else
18     {
19         for(int i=2;i<=n;++i)x[i]=c[i]-c[i-1];
20         for(int i=2;i<=n;++i)y[i]=t[i]-t[i-1];
21         sort(x+1,x+n+1);
22         sort(y+1,y+n+1);
23         bool yes=1;
24         for(int i=1;i<=n;++i)if(x[i]!=y[i])yes=0;
25         if(yes)puts("Yes");
26         else puts("No");
27     }
28     return 0; 
29 }
View Code

 

F.

题解:离线询问,线段树维护dfs序,查询相当于区间min,每次转移一条边相当于区间add

  1 #include<bits/stdc++.h>
  2 #define ll long long
  3 #define maxn 500005
  4 using namespace std;
  5 const ll inf = (ll)1e17;
  6 int n,q;
  7 int fa[maxn];
  8 ll ww[maxn];
  9 struct edge
 10 {
 11     int to,next;
 12     ll w;
 13 }e[maxn];
 14 int head[maxn],p;
 15 void addedge(int u,int v,ll w)
 16 {
 17     e[++p].to=v;e[p].w=w;e[p].next=head[u];head[u]=p;
 18 }
 19 struct Query
 20 {
 21     int v,l,r,id;
 22     Query(){};
 23     Query(int V,int L,int R,int ID){v=V;l=L;r=R;id=ID;} 
 24 };
 25 ll Ans[maxn];
 26 vector<Query> Q[maxn];
 27 struct Segmenttree
 28 {
 29     ll minv[maxn<<2],addv[maxn<<2];
 30     void pushup(int rt)
 31     {
 32         minv[rt]=min(minv[rt<<1],minv[rt<<1|1]);
 33     }
 34     void pushdown(int rt)
 35     {
 36         if(addv[rt])
 37         {
 38             ll t=addv[rt];
 39             minv[rt<<1]+=t;minv[rt<<1|1]+=t;
 40             addv[rt<<1]+=t;addv[rt<<1|1]+=t;
 41             addv[rt]=0;
 42         }
 43     }
 44     void update(int rt,int l,int r,int pos,ll w)
 45     {
 46         int mid=(l+r)>>1;
 47         if(l==r)
 48         {
 49             addv[rt]=0;minv[rt]=w;
 50             return;
 51         }
 52         if(pos<=mid)update(rt<<1,l,mid,pos,w);
 53         else update(rt<<1|1,mid+1,r,pos,w);
 54         pushup(rt);
 55     }
 56     void add(int rt,int l,int r,int ql,int qr,ll w)
 57     {
 58         if(ql>qr)return;
 59         int mid=(l+r)>>1;
 60         if(ql<=l&&r<=qr)
 61         {
 62             addv[rt]+=w;minv[rt]+=w;
 63             return;
 64         }
 65         pushdown(rt);
 66         if(ql<=mid)add(rt<<1,l,mid,ql,qr,w);
 67         if(qr>mid)add(rt<<1|1,mid+1,r,ql,qr,w);
 68         pushup(rt);
 69     }
 70     ll query(int rt,int l,int r,int ql,int qr)
 71     {
 72         ll ans=inf;
 73         int mid=(l+r)>>1;
 74         if(ql<=l&&r<=qr)return minv[rt];
 75         pushdown(rt);
 76         if(ql<=mid)ans=min(ans,query(rt<<1,l,mid,ql,qr));
 77         if(qr>mid)ans=min(ans,query(rt<<1|1,mid+1,r,ql,qr));
 78         pushup(rt);
 79         return ans;
 80     }
 81 }sgt;
 82 int size[maxn],lpos[maxn],rpos[maxn],cnt;
 83 ll dis[maxn];
 84 void dfs(int u)
 85 {
 86     size[u]=1;
 87     lpos[u]=++cnt;
 88     for(int i=head[u];i;i=e[i].next)
 89     {
 90         int v=e[i].to;ll w=e[i].w;
 91         dis[v]=dis[u]+w;
 92         dfs(v);
 93         size[u]+=size[v];
 94     }
 95     rpos[u]=cnt;
 96     if(size[u]==1)sgt.update(1,1,n,lpos[u],dis[u]);
 97     else sgt.update(1,1,n,lpos[u],inf);
 98 }
 99 void dfs2(int u)
100 {
101     for(int i=0;i<Q[u].size();++i)
102     {
103         int id=Q[u][i].id,l=Q[u][i].l,r=Q[u][i].r;
104         Ans[id]=sgt.query(1,1,n,l,r);
105     }
106     for(int i=head[u];i;i=e[i].next)
107     {
108         int v=e[i].to;ll w=e[i].w;
109         sgt.add(1,1,n,lpos[v],rpos[v],-w);
110         sgt.add(1,1,n,1,lpos[v]-1,w);
111         sgt.add(1,1,n,rpos[v]+1,n,w);
112         dfs2(v);
113         sgt.add(1,1,n,lpos[v],rpos[v],w);
114         sgt.add(1,1,n,1,lpos[v]-1,-w);
115         sgt.add(1,1,n,rpos[v]+1,n,-w);
116     }
117 }
118 int main()
119 {
120     scanf("%d%d",&n,&q);
121     for(int i=2;i<=n;++i)
122     {
123         int x;ll w;
124         scanf("%d%I64d",&x,&w);
125         fa[i]=x;ww[i]=w;
126     }
127     for(int i=n;i>=2;--i)addedge(fa[i],i,ww[i]);
128     for(int i=1;i<=q;++i)
129     {
130         int v,l,r;
131         scanf("%d%d%d",&v,&l,&r);
132         Q[v].push_back(Query(v,l,r,i));
133     }
134     dfs(1);
135     dfs2(1);
136     for(int i=1;i<=q;++i)printf("%I64d\n",Ans[i]);
137     return 0;
138 }
View Code

 

G.

题解:

大讨论博弈,细节巨多,而且操作有点强;

先考虑一开始没有白点的情况:

记d[u]为点u的度数

(一)若存在u,d[u]>=4,显然白的赢;(因为白色取了这个点,那么再任意取两个相邻点就可以)

(二)若任意u,d[u]<=2,则为一条链,显然平局;

(三)若存在u,d[u]==3;

  (1)存在这样的u,d[u]==3且相邻三个点中度数有两个>1,那么一定是白的赢(白的选这个点,黑的堵一个点,白的再选一个度数>1的点,显然可以构成链)

  (2)不存在这样的u,d[u]==3且相邻三个点中有两个度数>1:

    那么一定是一条链,其中一头或两头挂着一个两分叉:

    ①一分叉:显然平局;

    ②两分叉:(这种情况有坑)

      1.链上偶数个点,白的赢;

      (白的先选一头的2号点(d[u]=3的那个点旁边的一个d[u]=2的点),然后黑的必须堵1号点(就是d[u]=3的那个点),

      然后白的选4号点,黑的堵3号点,……,白的选2n号点,黑的堵2n-1号点,然后白的选2n+1号点,白的赢了)

      2.链上奇数个点,显然平局;

下面考虑一开始的白色点怎么处理:

这个操作有点强,把一个白点变换为一个未涂色的点1下面挂着一个点2,点2下面挂着两个叶子点3点4;

考虑为什么是对的:黑的和白的显然最优策略下都不能在这4个点中连成链,而且这4个点只有点1和外界相连;

         那么白的最优策略显然就是选1,达到了与白点等价的效果;

 1 #include<bits/stdc++.h>
 2 #define maxn 500005
 3 using namespace std;
 4 int T,n;
 5 struct edge
 6 {
 7     int to,next;
 8 }e[maxn*8];
 9 int head[maxn*4],p;
10 void addedge(int u,int v)
11 {
12     e[++p].to=v;e[p].next=head[u];head[u]=p;
13     e[++p].to=u;e[p].next=head[v];head[v]=p;
14 }
15 char col[maxn*4];
16 int d[maxn*4];
17 int has[5];
18 int main()
19 {
20     scanf("%d",&T);
21     while(T--)
22     {
23         scanf("%d",&n);
24         p=0;
25         for(int i=1;i<=n*4;++i)head[i]=0,d[i]=0,col[i]=0;
26         memset(has,0,sizeof(has));
27         for(int i=1;i<n;++i)
28         {
29             int u,v;
30             scanf("%d%d",&u,&v);
31             d[u]++;d[v]++;
32             addedge(u,v);
33         }
34         scanf("%s",col+1);
35         int cnt=n;
36         for(int i=1;i<=n;++i)if(col[i]=='W')
37         {
38             d[i]++;
39             d[++cnt]=3;
40             addedge(i,cnt);
41             d[++cnt]=1;
42             addedge(cnt-1,cnt);
43             d[++cnt]=1;
44             addedge(cnt-2,cnt);
45         }
46         n=cnt;
47         for(int i=1;i<=n;++i)has[min(d[i],4)]++;
48         if(has[4])puts("White");
49         else if(has[3])
50         {
51             bool yes=0;
52             for(int u=1;u<=n;++u)if(d[u]==3)
53             {
54                 int num=0;
55                 for(int i=head[u];i;i=e[i].next)
56                 {
57                     int v=e[i].to;
58                     if(d[v]>1)num++;
59                 }
60                 if(num>=2)yes=1;
61             }
62             if(yes)puts("White");
63             else
64             {
65                 if(has[3]==2)
66                 {
67                     if(n&1)puts("White");
68                     else puts("Draw");
69                 }
70                 else puts("Draw");
71             }
72         }
73         else puts("Draw");
74     }
75     return 0;
76 }
View Code

 

posted @ 2019-02-10 09:50  幽蝶  阅读(163)  评论(0编辑  收藏  举报