Codeforces Round #636 (Div. 3)题解
Posted johnran
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Codeforces Round #636 (Div. 3)题解相关的知识,希望对你有一定的参考价值。
A. 给你一个n,解方程,(1+2+4+...+2^(k-1))*x=n,保证k>1。
枚举k,可以整除时输出一个数。
#include<bits/stdc++.h> #define all(x) x.begin(),x.end() #define fi first #define sd second #define lson (nd<<1) #define rson (nd+nd+1) #define PB push_back #define mid (l+r>>1) #define MP make_pair #define SZ(x) (int)x.size() using namespace std; typedef long long LL; typedef vector<int> VI; typedef pair<int,int> PII; inline int read(){ int res=0, f=1;char ch=getchar(); while(ch<‘0‘|ch>‘9‘){if(ch==‘-‘)f=-1;ch=getchar();} while(ch>=‘0‘&&ch<=‘9‘){res=res*10+ch-‘0‘;ch=getchar();} return res*f; } const int MAXN = 200‘005; const int MOD = 1000000007; void addmod(int& a, int b){a+=b;if(a>=MOD)a-=MOD;} int mulmod(int a, int b){return 1ll*a*b%MOD;} template<typename T> void chmin(T& a, T b){if(a>b)a=b;} template<typename T> void chmax(T& a, T b){if(b>a)a=b;} void solve(){ int n=read(); for(int i=2;i<=30;++i){ int v=(1<<i)-1; if(n%v==0){ cout<<n/v<<endl; return; } } } int main(){ int t=read(); while(t--){ solve(); } return 0; }
B. 给一个偶数n,构造一个数组,前面都是偶数,后面都是奇数,且互不相同。且前面n/2个数的和与后面n/2个数的和相等。
首先n/2不是偶数直接输出“NO”,然后就随便搞搞。
#include<bits/stdc++.h> #define all(x) x.begin(),x.end() #define fi first #define sd second #define lson (nd<<1) #define rson (nd+nd+1) #define PB push_back #define mid (l+r>>1) #define MP make_pair #define SZ(x) (int)x.size() using namespace std; typedef long long LL; typedef vector<int> VI; typedef pair<int,int> PII; inline int read(){ int res=0, f=1;char ch=getchar(); while(ch<‘0‘|ch>‘9‘){if(ch==‘-‘)f=-1;ch=getchar();} while(ch>=‘0‘&&ch<=‘9‘){res=res*10+ch-‘0‘;ch=getchar();} return res*f; } const int MAXN = 200‘005; const int MOD = 1000000007; void addmod(int& a, int b){a+=b;if(a>=MOD)a-=MOD;} int mulmod(int a, int b){return 1ll*a*b%MOD;} template<typename T> void chmin(T& a, T b){if(a>b)a=b;} template<typename T> void chmax(T& a, T b){if(b>a)a=b;} void solve(){ int n=read(); if((n/2)&1){ cout<<"NO"<<endl; }else{ cout<<"YES"<<endl; for(int i=1;i<=n/2;++i){ cout<<2*i<<" "; } for(int i=1;i<=n/2-1;++i){ cout<<2*i-1<<" "; } cout<<3*n/2-1<<endl; } } int main(){ int t=read(); while(t--){ solve(); } return 0; }
C. 给一个长度为n的数组,里面没有0。求一个正负交替的子序列,其和最大。
首先可以发现,一段连续的正数和负数只能选一个,直接贪心选最大。
#include<bits/stdc++.h> #define all(x) x.begin(),x.end() #define fi first #define sd second #define lson (nd<<1) #define rson (nd+nd+1) #define PB push_back #define mid (l+r>>1) #define MP make_pair #define SZ(x) (int)x.size() using namespace std; typedef long long LL; typedef vector<int> VI; typedef pair<int,int> PII; inline LL read(){ LL res=0, f=1;char ch=getchar(); while(ch<‘0‘|ch>‘9‘){if(ch==‘-‘)f=-1;ch=getchar();} while(ch>=‘0‘&&ch<=‘9‘){res=res*10+ch-‘0‘;ch=getchar();} return res*f; } const int MAXN = 200‘005; const int MOD = 1000000007; void addmod(int& a, int b){a+=b;if(a>=MOD)a-=MOD;} int mulmod(int a, int b){return 1ll*a*b%MOD;} template<typename T> void chmin(T& a, T b){if(a>b)a=b;} template<typename T> void chmax(T& a, T b){if(b>a)a=b;} void solve(){ LL n=read(); vector<LL> a(n); vector<LL> b; for(int i=0;i<n;++i){ a[i]=read(); if(i!=0){ if(b.back()*a[i]>0){ b.back()=max(b.back(),a[i]); }else{ b.PB(a[i]); } }else{ b.PB(a[0]); } } cout<<accumulate(all(b),0ll)<<endl; } int main(){ LL t=read(); while(t--){ solve(); } return 0; }
D. 给你n个数的数组,n为偶数。每一个数都不超过k,修改之后的值也不能超过k。现在求最小的修改次数,使得a[i]+a[n-i+1]=const。
考虑一下右边的这个常数,我们会发现,对于每一个二元组,是可以O(1)得到某一个常数对应的修改次数的。直接差分,O(n)做完。
#include<bits/stdc++.h> #define all(x) x.begin(),x.end() #define fi first #define sd second #define lson (nd<<1) #define rson (nd+nd+1) #define PB push_back #define mid (l+r>>1) #define MP make_pair #define SZ(x) (int)x.size() using namespace std; typedef long long LL; typedef vector<int> VI; typedef pair<int,int> PII; inline int read(){ int res=0, f=1;char ch=getchar(); while(ch<‘0‘|ch>‘9‘){if(ch==‘-‘)f=-1;ch=getchar();} while(ch>=‘0‘&&ch<=‘9‘){res=res*10+ch-‘0‘;ch=getchar();} return res*f; } const int MAXN = 200‘005; const int MOD = 1000000007; void addmod(int& a, int b){a+=b;if(a>=MOD)a-=MOD;} int mulmod(int a, int b){return 1ll*a*b%MOD;} template<typename T> void chmin(T& a, T b){if(a>b)a=b;} template<typename T> void chmax(T& a, T b){if(b>a)a=b;} void solve(){ int n=read(),k=read(); vector<int> a(2*k+5,0); vector<int> num(n+1); for(int i=1;i<=n;++i)num[i]=read(); for(int i=1;i<=n/2;++i){ int x=num[i]+num[n-i+1]; int l1=x-max(num[i],num[n-i+1])+1; int r1=x; int l2=x+1; int r2=x+k-min(num[i],num[n-i+1])+1; int l3=2; int r3=max(l3,l1); int l4=r2; int r4=2*k+1; a[l1]+=1; a[r1]-=1; a[l2]+=1; a[r2]-=1; a[l3]+=2; a[r3]-=2; a[l4]+=2; a[r4]-=2; } for(int i=1;i<=2*k;++i)a[i]=(a[i-1]+a[i]); cout<<*min_element(a.begin()+2,a.begin()+2*k+1)<<endl; } int main(){ int t=read(); while(t--){ solve(); } return 0; } /* 1 2 1 1 1 */
E. 给你一个n个点,m条边的图,和m个值,要求给边分配权重,使得从a->b->c,权重和最小。
首先考虑一种简单的情况,如果只有两个点。那么毫无疑问,我们直接bfs出最短路,贪心选择最小的边即可。现在变成三个点,其实也差不多,我们要走的路径,其实都是“一”,"Y","V"字型的。即,有一些边我们是要走两次的,肯定要选权值最小的几条边,其他的就贪心的去选就行了。现在如果想去找a->b和c->b经过了哪些点是行不通的,无论是bfs还是dfs都跑不通。原因是最短路可能不止一条,这直接导致两条路径不重合,代价变大(蒟蒻哭泣)。正确的做法是,枚举一个点,得到这个点与a,b,c,三个点的距离。然后到b的距离安排上最小的一些边权(因为要算两次),然后贪心的去选取其他的边权。正确性也是显然的,首先,两条最短路上的点一定比非路径上的点优(很显然),其次是分叉点一定比其他点优。
#include<bits/stdc++.h> #define all(x) x.begin(),x.end() #define fi first #define sd second #define lson (nd<<1) #define rson (nd+nd+1) #define PB push_back #define mid (l+r>>1) #define MP make_pair #define SZ(x) (int)x.size() using namespace std; typedef long long LL; typedef vector<int> VI; typedef pair<int,int> PII; inline int read(){ int res=0, f=1;char ch=getchar(); while(ch<‘0‘|ch>‘9‘){if(ch==‘-‘)f=-1;ch=getchar();} while(ch>=‘0‘&&ch<=‘9‘){res=res*10+ch-‘0‘;ch=getchar();} return res*f; } const int MAXN = 200‘005; const int MOD = 1000000007; void addmod(int& a, int b){a+=b;if(a>=MOD)a-=MOD;} int mulmod(int a, int b){return 1ll*a*b%MOD;} template<typename T> void chmin(T& a, T b){if(a>b)a=b;} template<typename T> void chmax(T& a, T b){if(b>a)a=b;} void solve(){ int n=read(),m=read(),a=read(),b=read(),c=read(); --a;--b;--c; vector<vector<int>> G(n,vector<int>()); vector<int> val(m); for(int i=0;i<m;++i)val[i]=read(); sort(all(val)); vector<LL> sum(m+1,0); for(int i=1;i<=m;++i)sum[i]=sum[i-1]+val[i-1]; for(int i=1;i<=m;++i){ int u=read();int v=read(); --u;--v; G[u].PB(v);G[v].PB(u); } LL ans=1e18; auto bfs=[&](int x){ vector<int> d(n,-1); queue<int> q; q.push(x); d[x]=0; while(!q.empty()){ int u=q.front(); q.pop(); for(auto it:G[u]){ if(d[it]!=-1)continue; else{ d[it]=d[u]+1; q.push(it); } } } return d; }; auto da=bfs(a),db=bfs(b),dc=bfs(c); for(int i=0;i<n;++i){ int dx=da[i],dy=db[i],dz=dc[i]; if(dx+dy+dz>m)continue; else ans=min(ans,sum[dy]+sum[dx+dy+dz]); } cout<<ans<<endl; } int main(){ int t=read(); while(t--){ solve(); } return 0; } /* 1 4 4 1 3 4 1 2 3 4 1 2 2 3 3 4 1 4 4 */
F. 现在有一个排列,长度为n。现在的情况是,给从右端点(r=2...n),左端点随便选(l<r),的n-1个区间段,但是这个区间段是排序之后的。n-1个区间段是随机给的,现在要复原这个排列。
枚举第一个元素,考虑对所有的区间段删掉这个元素,那么一定只有一个区间段长度为1(不是则这个第一个值不合法)。原因很显然,因为其他的删不到第一个元素。现在变成了一个子问题了,只不过第一个值变成了那个长度为1的子段的值。
这样就能得到一些解,但是很神奇的是,这这是一个必要条件,不一定是充分的。所以我们还需要要验证这n-1个子段能不能生成。
#include<bits/stdc++.h> #define all(x) x.begin(),x.end() #define fi first #define sd second #define lson (nd<<1) #define rson (nd+nd+1) #define PB push_back #define mid (l+r>>1) #define MP make_pair #define SZ(x) (int)x.size() using namespace std; typedef long long LL; typedef vector<int> VI; typedef pair<int,int> PII; inline int read(){ int res=0, f=1;char ch=getchar(); while(ch<‘0‘|ch>‘9‘){if(ch==‘-‘)f=-1;ch=getchar();} while(ch>=‘0‘&&ch<=‘9‘){res=res*10+ch-‘0‘;ch=getchar();} return res*f; } const int MAXN = 200‘005; const int MOD = 1000000007; void addmod(int& a, int b){a+=b;if(a>=MOD)a-=MOD;} int mulmod(int a, int b){return 1ll*a*b%MOD;} template<typename T> void chmin(T& a, T b){if(a>b)a=b;} template<typename T> void chmax(T& a, T b){if(b>a)a=b;} void solve(){ int n=read(); vector<set<int>> a(n-1); for(int i=0;i<n-1;++i){ int k=read(); for(int j=0;j<k;++j){ a[i].insert(read()); } } for(int fst=1;fst<=n;++fst){ auto b=a; int ok=1; vector<int> ans; ans.PB(fst); for(int i=0;i<n-1;++i){ if(SZ(b[i])>0&&b[i].count(fst)){ b[i].erase(b[i].find(fst)); } } for(int iter=1;iter<n;++iter){ int cnt=0; int nxt=-1; for(int i=0;i<n-1;++i){ if(SZ(b[i])==1){ ++cnt; nxt=*b[i].begin(); b[i].clear(); } } if(cnt>1||cnt==0){ ok=0;break; } ans.PB(nxt); for(int i=0;i<n-1;++i){ if(SZ(b[i])>0&&b[i].count(nxt)){ b[i].erase(b[i].find(nxt)); } } } if(!ok)continue; else{ for(int i=0;i<n-1;++i){ int okok=0; for(int j=0;j<n;++j){ set<int> s;s.insert(ans[j]); for(int k=j+1;k<n;++k){ s.insert(ans[k]); if(a[i]==s){ okok=1; break; } } } if(!okok){ ok=0; break; } } if(ok){ for(int i=0;i<n;++i)cout<<ans[i]<<" "[i==n-1]; return; } } } } int main(){ int t=read(); while(t--){ solve(); } return 0; }
以上是关于Codeforces Round #636 (Div. 3)题解的主要内容,如果未能解决你的问题,请参考以下文章
Codeforces Round #636 (Div. 3)
Codeforces Round #636 (Div. 3)题解
codeforces Round #636 D. Constant Palindrome Sum
Codeforces Round #636 (Div. 3) E—Weights Distributing