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 }
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 ",ans); 21 return 0; 22 }
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 ",ans); 22 } 23 else printf("%d ",vis[p]); 24 } 25 else printf("%d ",(1<<p)-1); 26 } 27 return 0; 28 }
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 ",dp[m][0][0]); 38 return 0; 39 }
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 }
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 ",Ans[i]); 137 return 0; 138 }
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 }