Codeforces Round #690 (Div. 3)(A->F)(F二分)
A:http://codeforces.com/contest/1462/problem/A
#include<iostream> #include<cstring> #include<map> #include<stack> #include<queue> #include<algorithm> #include<cstdio> #include<cmath> #include<string.h> using namespace std; typedef long long ll; const intmaxn=2e4+10; const int inf=99999999; int a[maxn]; int main() { int t; cin>>t; while(t--) { int n; cin>>n; for(int i=1;i<=n;i++) cin>>a[i]; int cnt=0; int l=1; int ok=0; int md=n-1; while(1) {if(cnt==n) break; if(!ok) { cout<<a[l]<<" "; l=l+md; md--; ok=1; } else { cout<<a[l]<<" "; l=l-md; md--; ok=0; } cnt++; } cout<<endl; } }
B:http://codeforces.com/contest/1462/problem/B
題意:
給定一個字串,能否最多刪除一段連續的一段使得剩下的為“2020”
解析:
無非就六種情況,直接列一遍就好了
#include<iostream> #include<cstring> #include<map> #include<stack> #include<queue> #include<algorithm> #include<cstdio> #include<cmath> #include<string.h> using namespace std; typedef long long ll; const int maxn=2e4+10; const int inf=99999999; int a[maxn]; int main() { int t; cin>>t; while(t--) { int n; cin>>n; string s; cin>>s; int le=s.length(); if(s=="2020") { cout<<"YES"<<endl; } else { if(s[0]=='2'&&s[1]=='0'&&s[2]=='2'&&s[3]=='0') { cout<<"YES"<<endl; } else if(s[0]=='2'&&s[1]=='0'&&s[2]=='2'&&s[le-1]=='0') { cout<<"YES"<<endl; } else if(s[0]=='2'&&s[1]=='0'&&s[le-2]=='2'&&s[le-1]=='0') { cout<<"YES"<<endl; } else if(s[0]=='2'&&s[le-3]=='0'&&s[le-2]=='2'&&s[le-1]=='0') { cout<<"YES"<<endl; } else if(s[le-4]=='2'&&s[le-3]=='0'&&s[le-2]=='2'&&s[le-1]=='0') { cout<<"YES"<<endl; } else cout<<"NO"<<endl; } } }
C:http://codeforces.com/contest/1462/problem/C
題意:
輸出最小的數位和等於x並且各個數位都不一樣的值
解析:
在紙上寫了一下,發現每一個存在的答案,都是從個位開始,數字越來越小。所以從9開始列舉即可。
#include<iostream> #include<cstring> #include<map> #include<stack> #include<queue> #include<algorithm> #include<cstdio> #include<cmath> #include<string.h> using namespace std; typedef long long ll; const int maxn=2e4+10; const int inf=99999999; int a[maxn]; int main() { int t; cin>>t; while(t--) { int n; cin>>n; if(n<=9) { cout<<n<<endl;continue; } if(n>45) { cout<<"-1"<<endl;continue; } int sum=0; int num[111]; int tot=0,ok=0; int all=n; for(int i=9;i>=1;i--) { if(sum+i>n) continue; sum+=i; num[tot++]=i; if(sum==n) { ok=1;break; } } if(ok) { for(int i=tot-1;i>=0;i--) cout<<num[i]; cout<<endl; } else cout<<"-1"<<endl; } }
D:http://codeforces.com/contest/1462/problem/D
題意:
給出一個序列,每個數可以與左或右合併,這算一個操作。求使得所有數相同的最少運算元。
解析:
其實所謂所有數相同,就是把整個原數分成幾份,每一份加和相等。
所以先求出總和sum,列舉它的因子x,求一下每份和為x , sum / x的所需運算元,求個最小值即可。
#include<iostream> #include<cstring> #include<map> #include<algorithm> #include<stack> #include<queue> #include<cstdio> #include<cmath> #include<string.h> using namespace std; typedef long long ll; const int maxn=3e3+10; const int inf=99999999; int a[maxn]; int n; ll num[maxn]; ll sum=0; int ac(int x) { int all=sum/x; int ans=0; int cnt=0; int ok = 0 ; for(int i=1;i<=n;i++) { if(a[i]>x) return -1; if(a[i]==x&&ans<x&&ans>0) return -1; if(ans+a[i]==x) { if(ans>0) cnt++; ans=0; } else if(ans+a[i]<x) { if(ans>0) cnt++; ans+=a[i]; } else { return -1; } } return cnt; } int main() { int t; scanf("%d",&t); while(t--) { cin>>n; sum = 0 ; for(int i=1;i<=n;i++) cin>>a[i],sum+=a[i]; int no=0; for(int i=1;i<n;i++) { if(a[i]!=a[i+1]) { no=1;break; } } if(!no) { cout<<"0"<<endl;continue; } // cout<<ac(sum/2)<<endl; int ok = 0; int an=inf; for(int i=2;i*i<=sum;i++) { if(sum%i==0) { int md1=ac(i); int md2=ac(sum/i); if(md1!=-1) { an=min(an,md1); // cout<<i<<"--1"<<endl; ok=1; } if(md2!=-1) { an=min(an,md2); // cout<<i<<"--2"<<endl; ok=1; } } } if(!ok) cout<<n-1<<endl;//不存在,那麼全合併即可 else cout<<an<<endl; } }
E1:http://codeforces.com/contest/1462/problem/E1
題意:
求有多少組ai,aj,az,max(ai,aj,az)-min(ai,aj,az)<=2
解析:
由於這三個數並不需要挨著,所以順序無所謂。那麼可以先從小到大排個序。
列舉最小值ai,向右找到第一個aj-ai>2的位置,那麼i~j之間的數字隨便選兩個和ai組合就是一組答案,那麼答案就是C(j-i-1,2),累加即可。
#include<iostream> #include<cstring> #include<map> #include<algorithm> #include<stack> #include<queue> #include<cstdio> #include<cmath> #include<string.h> using namespace std; typedef long long ll; const int maxn=2e5+10; const int inf=99999999; int a[maxn]; int n; int main() { int t; scanf("%d",&t); while(t--) { cin>>n; for(int i=1;i<=n;i++) cin>>a[i]; sort(a+1,a+1+n); ll sum = 0 ; int r=2; for(int i=1;i<=n;i++) { while(a[r]-a[i]<=2&&r<=n) r++; ll cnt=(r-i-1); if(cnt>=2) sum+=cnt*(cnt-1)/2; } cout<<sum<<endl; } }
E2:http://codeforces.com/contest/1462/problem/E2
與E1不同的是,所選數目以及最大差值可以自定義。
與E1思路相同,只是難點在求組合數這邊。考慮m只有100,那麼提前預處理一下組合數即可。
#include<iostream> #include<cstring> #include<map> #include<algorithm> #include<stack> #include<queue> #include<cstdio> #include<cmath> #include<string.h> using namespace std; typedef long long ll; const int maxn=2e5+10; const int inf=99999999; const int mod=1e9+7; int a[maxn]; int n,m,k; int c[maxn][130]; void init() { c[0][0]=1; c[1][0]=1;c[1][1]=1; for(int i=2;i<maxn;i++) { for(int j=0;j<=105&&j<=i;j++) { c[i][j]=(c[i-1][j-1]+c[i-1][j])%mod; } } } int main() { int t; init(); scanf("%d",&t); while(t--) { cin>>n>>m>>k; for(int i=1;i<=n;i++) cin>>a[i]; sort(a+1,a+1+n); ll sum=0; int r=1; for(int i=1;i<=n;i++) { while(a[r]-a[i]<=k&&r<=n) r++; ll cnt=(r-i-1); if(cnt>=m-1) { sum=(sum+c[cnt][m-1])%mod; } } cout<<sum<<endl; } }
F:http://codeforces.com/contest/1462/problem/F
題意:
給你n個線段,代表線段的左右端點,問最少刪幾條線段,使得剩下當中存在一個線段與所有剩下的所有線段都有交集。
解析:
考慮列舉每一條線段,求以此線段與所有線段都有交集,需要刪除的線段數。
那麼對於此線段[L,R],右端點小於L的,與它無交集,需要全刪掉。同理左端點大於R的線段,也需要都刪掉。
那麼剩下的問題,就是需要刪幾個了。
預存一下所有的L,R,放到x[],y[]裡面。對它們進行從小到大的排序。
對於當前列舉到的[L,R],求小於L的右端點不好求,那就先求>=L的,就是:lower_bound(y+1,y+1+n,a[i])-y; 再減1,就是小於L的了:lower_bound(y+1,y+1+n,a[i])-y-1;
然後求大於R的左端點,n-(upper_bound(x+1,x+1+n,b[i])-x)+1;
加起來,每次取最小即可。
#include<iostream> #include<cstring> #include<map> #include<algorithm> #include<stack> #include<queue> #include<cstdio> #include<cmath> #include<string.h> using namespace std; typedef long long ll; const int maxn=2e5+10; const int inf=99999999; const int mod=1e9+7; int a[maxn],b[maxn],x[maxn],y[maxn]; int main() { int t; scanf("%d",&t); while(t--) { int n; cin>>n; for(int i=1;i<=n;i++) { cin>>a[i]>>b[i]; x[i]=a[i]; y[i]=b[i]; } sort(x+1,x+1+n); sort(y+1,y+1+n); ll minn = inf; for(int i=1;i<=n;i++) { ll l=lower_bound(y+1,y+1+n,a[i])-y-1; ll r=n-(upper_bound(x+1,x+1+n,b[i])-x)+1; minn=min(minn,l+r); } cout<<minn<<endl; } }