Codeforces Round #690 (Div. 3)——解題報告
A題——Favorite Sequence
根據題意直接模擬即可。
#include <bits/stdc++.h> #define PI atan(1.0)*4 #define rp(i,s,t) for (register int i = (s); i <= (t); i++) #define RP(i,t,s) for (register int i = (t); i >= (s); i--) #define sc(x) scanf("%d",&x) #define scl(x) scanf("%lld",&x) #define ll long long #define ull unsigned long long #define mst(a,b) memset(a,b,sizeof(a)) #define lson l,m,rt<<1 #define rson m+1,r,rt<<1|1 #define pii pair<int,int> #define pll pair<ll,ll> #define pil pair<int,ll> #define m_p make_pair #define p_b push_back #define ins insert #define era erase #define INF 0x3f3f3f3f #define LINF 0x3f3f3f3f3f3f3f3f #define dg if(debug) #define outval(a) cout << "Debuging...|" << #a << ": " << a << "\n"; using namespace std; int debug = 0; ll gcd(ll a,ll b){ return b?gcd(b,a%b):a; } ll lcm(ll a,ll b){ return a/gcd(a,b)*b; } inline int read(){ int s=0,f=1; char ch=getchar(); while(ch<'0'||ch>'9'){ if(ch=='-') f=-1; ch=getchar(); } while(ch>='0'&&ch<='9'){ s=s*10+ch-'0'; ch=getchar(); } return s*f; } const int N = 3e2+7; int a[N]; void solve(){ int n=read(); rp(i,1,n) a[i]=read(); int l=1,r=n; int f=1; int cnt=0; while(l<=r){ if(f==1) cout<<a[l++],cnt++; else cout<<a[r--],cnt++; f^=1; if(cnt==n) cout<<endl; else cout<<" "; } } int main(){ //ios::sync_with_stdio(false); cin.tie(0); cout.tie(0); #ifdef ONLINE_JUDGE #else freopen("in.txt", "r", stdin); //debug = 1; #endif time_t beg, end; //if(debug) beg = clock(); int T=read(); while(T--) solve(); /* if(debug) { end = clock(); printf("time:%.2fs\n", 1.0 * (end - beg) / CLOCKS_PER_SEC); } */ return 0; }
B題——Last Year's Substring
暴力的想法是直接列舉刪除[i,j]區間判斷就行了,然後可以發現當i確定後,j也就隨之確定,這樣就可以省掉一個迴圈,而且易知i的長度也不能大於4(優化),簡化後也就是題解的做法。
trick:樣例已經給出了的2020的情況。
比較好寫且簡單的做法(題解):因為2020的長度為4,所以刪除區間的長度為n-4,那麼最終區間的可能也就定了,總共五種。
判斷他們是否等於2020就行了。
#include <bits/stdc++.h> #define PI atan(1.0)*4 #define rp(i,s,t) for (register int i = (s); i <= (t); i++) #define RP(i,t,s) for (register int i = (t); i >= (s); i--) #define sc(x) scanf("%d",&x) #define scl(x) scanf("%lld",&x) #define ll long long #define ull unsigned long long #define mst(a,b) memset(a,b,sizeof(a)) #define lson l,m,rt<<1 #define rson m+1,r,rt<<1|1 #define pii pair<int,int> #define pll pair<ll,ll> #define pil pair<int,ll> #define m_p make_pair #define p_b push_back #define ins insert #define era erase #define INF 0x3f3f3f3f #define LINF 0x3f3f3f3f3f3f3f3f #define dg if(debug) #define outval(a) cout << "Debuging...|" << #a << ": " << a << "\n"; using namespace std; int debug = 0; ll gcd(ll a,ll b){ return b?gcd(b,a%b):a; } ll lcm(ll a,ll b){ return a/gcd(a,b)*b; } inline int read(){ int s=0,f=1; char ch=getchar(); while(ch<'0'||ch>'9'){ if(ch=='-') f=-1; ch=getchar(); } while(ch>='0'&&ch<='9'){ s=s*10+ch-'0'; ch=getchar(); } return s*f; } void solve(){ int n=read(); string s;cin>>s; rp(i,0,3){ if(s.substr(0,i)+s.substr(n-4+i,4-i)=="2020"){ puts("YES"); return ; } } puts("NO"); } int main(){ //ios::sync_with_stdio(false); cin.tie(0); cout.tie(0); #ifdef ONLINE_JUDGE #else freopen("in.txt", "r", stdin); //debug = 1; #endif time_t beg, end; //if(debug) beg = clock(); int T=read(); while(T--) solve(); /* if(debug) { end = clock(); printf("time:%.2fs\n", 1.0 * (end - beg) / CLOCKS_PER_SEC); } */ return 0; }
C題——Unique Number
我的做法是直接手算,因為n最大才50,而大於等於45的都是不行的(這一點應該不難推出)。
手推構造一下可以得出(至於怎麼構造的,請參考題解)
當n<=9時,答案就是n,19,29,...,89最多可以表示到17,189,289,...,789最多可以表示到24,之後的類推就行了,發現上界為123456789,最多表示為45。
#include <bits/stdc++.h> #define PI atan(1.0)*4 #define rp(i,s,t) for (register int i = (s); i <= (t); i++) #define RP(i,t,s) for (register int i = (t); i >= (s); i--) #define sc(x) scanf("%d",&x) #define scl(x) scanf("%lld",&x) #define ll long long #define ull unsigned long long #define mst(a,b) memset(a,b,sizeof(a)) #define lson l,m,rt<<1 #define rson m+1,r,rt<<1|1 #define pii pair<int,int> #define pll pair<ll,ll> #define pil pair<int,ll> #define m_p make_pair #define p_b push_back #define ins insert #define era erase #define INF 0x3f3f3f3f #define LINF 0x3f3f3f3f3f3f3f3f #define dg if(debug) #define outval(a) cout << "Debuging...|" << #a << ": " << a << "\n"; using namespace std; int debug = 0; ll gcd(ll a,ll b){ return b?gcd(b,a%b):a; } ll lcm(ll a,ll b){ return a/gcd(a,b)*b; } inline int read(){ int s=0,f=1; char ch=getchar(); while(ch<'0'||ch>'9'){ if(ch=='-') f=-1; ch=getchar(); } while(ch>='0'&&ch<='9'){ s=s*10+ch-'0'; ch=getchar(); } return s*f; } void solve(){ int x=read(); if(x>45) printf("-1\n"); else{ if(x<=9) printf("%d",x); else if(x<=17) printf("%d9",x-9); else if(x<=24) printf("%d89",x-17); else if(x<=30) printf("%d789",x-24); else if(x<=35) printf("%d6789",x-30); else if(x<=39) printf("%d56789",x-35); else if(x<=42) printf("%d456789",x-39); else if(x<=44) printf("%d3456789",x-42); else if(x==45) printf("123456789"); printf("\n"); } } int main(){ //ios::sync_with_stdio(false); cin.tie(0); cout.tie(0); #ifdef ONLINE_JUDGE #else freopen("in.txt", "r", stdin); //debug = 1; #endif time_t beg, end; //if(debug) beg = clock(); int T=read(); while(T--) solve(); /* if(debug) { end = clock(); printf("time:%.2fs\n", 1.0 * (end - beg) / CLOCKS_PER_SEC); } */ return 0; }
D題——Add to Neighbour and Remove
假設當前操作次數為i
因為每次操作都只是改變數所在集合的位置,那麼總和就是不變的,而且要求i次操作後每個集合元素和相等,因此每個集合的元素和就確定了,為sum/(n-i)。
什麼情況下i合法呢,根據上面可知,當(n-i)為sum的因子時是合法的。
這樣我們就可以列舉合法的操作次數,再貪心地從前往後維護每個集合就行了,最後判斷當前操作次數是否能夠滿足要求就行了。
#include <bits/stdc++.h> #define PI atan(1.0)*4 #define rp(i,s,t) for (register int i = (s); i <= (t); i++) #define RP(i,t,s) for (register int i = (t); i >= (s); i--) #define sc(x) scanf("%d",&x) #define scl(x) scanf("%lld",&x) #define ll long long #define ull unsigned long long #define mst(a,b) memset(a,b,sizeof(a)) #define lson l,m,rt<<1 #define rson m+1,r,rt<<1|1 #define pii pair<int,int> #define pll pair<ll,ll> #define pil pair<int,ll> #define m_p make_pair #define p_b push_back #define ins insert #define era erase #define INF 0x3f3f3f3f #define LINF 0x3f3f3f3f3f3f3f3f #define dg if(debug) #define outval(a) cout << "Debuging...|" << #a << ": " << a << "\n"; using namespace std; int debug = 0; ll gcd(ll a,ll b){ return b?gcd(b,a%b):a; } ll lcm(ll a,ll b){ return a/gcd(a,b)*b; } inline int read(){ int s=0,f=1; char ch=getchar(); while(ch<'0'||ch>'9'){ if(ch=='-') f=-1; ch=getchar(); } while(ch>='0'&&ch<='9'){ s=s*10+ch-'0'; ch=getchar(); } return s*f; } const int N = 3e3+7; int a[N]; void solve(){ int n=read(); int sum=0; rp(i,1,n) a[i]=read(),sum+=a[i]; rp(i,0,n-1){ if(sum%(n-i)!=0) continue; int res=sum/(n-i); int ff=0; int cur=0; int cnt=0; rp(j,1,n){ if(cur+a[j]>res){ ff=1; break; } else if(cur+a[j]==res){ cur=0; cnt++; } else cur+=a[j]; } if(cnt!=n-i) ff=1; // cout<<i<<" "<<ff<<endl; if(ff==0){ cout<<i<<endl; break; } } } int main(){ //ios::sync_with_stdio(false); cin.tie(0); cout.tie(0); #ifdef ONLINE_JUDGE #else freopen("in.txt", "r", stdin); //debug = 1; #endif time_t beg, end; //if(debug) beg = clock(); int T=read(); while(T--) solve(); /* if(debug) { end = clock(); printf("time:%.2fs\n", 1.0 * (end - beg) / CLOCKS_PER_SEC); } */ return 0; }
E題——Close Tuples
感覺比D題好想一點,屬於比較套路的題,第一眼還以為是三維偏序的題,最後發現是一道二分的簡單題。
首先我們需要對a陣列排個序,然後對於每個ai進行考慮,即先給集合選一個數。
先二分出最後一個小於等於ai+k的數的位置id。
在[i+1,id]中選出m-1個數(即)和ai湊成m個數就行了。
#include <bits/stdc++.h> #define PI atan(1.0)*4 #define rp(i,s,t) for (register int i = (s); i <= (t); i++) #define RP(i,t,s) for (register int i = (t); i >= (s); i--) #define sc(x) scanf("%d",&x) #define scl(x) scanf("%lld",&x) #define ll long long #define ull unsigned long long #define mst(a,b) memset(a,b,sizeof(a)) #define lson l,m,rt<<1 #define rson m+1,r,rt<<1|1 #define pii pair<int,int> #define pll pair<ll,ll> #define pil pair<int,ll> #define m_p make_pair #define p_b push_back #define ins insert #define era erase #define INF 0x3f3f3f3f #define LINF 0x3f3f3f3f3f3f3f3f #define dg if(debug) #define outval(a) cout << "Debuging...|" << #a << ": " << a << "\n"; using namespace std; int debug = 0; ll gcd(ll a,ll b){ return b?gcd(b,a%b):a; } ll lcm(ll a,ll b){ return a/gcd(a,b)*b; } inline int read(){ int s=0,f=1; char ch=getchar(); while(ch<'0'||ch>'9'){ if(ch=='-') f=-1; ch=getchar(); } while(ch>='0'&&ch<='9'){ s=s*10+ch-'0'; ch=getchar(); } return s*f; } const int N = 2e5+7; const ll mod = 1e9+7; int a[N]; ll fac[N]; ll quickPow(ll a, ll b, ll mod) { ll ans = 1; while(b) { if(b&1) ans=(ans*a)%mod; a=(a*a)%mod; b>>=1; } return ans; } ll inv(ll x){ return quickPow(x,mod-2,mod); } ll C(int n,int m){ return fac[n]*inv(fac[m])%mod*inv(fac[n-m])%mod; } void init(){ fac[0]=1; rp(i,1,N-7) fac[i]=(fac[i-1]*i)%mod; } void solve(){ int n=read(),m=read(),k=read(); rp(i,1,n) a[i]=read(); sort(a+1,a+1+n); ll ans=0; rp(i,1,n){ int id=upper_bound(a+1,a+1+n,a[i]+k)-a; id--; id=min(id,n); if(id-i>=m-1) ans=(ans+C(id-i,m-1)%mod)%mod; } cout<<ans<<endl; } int main(){ //ios::sync_with_stdio(false); cin.tie(0); cout.tie(0); #ifdef ONLINE_JUDGE #else freopen("in.txt", "r", stdin); //debug = 1; #endif time_t beg, end; //if(debug) beg = clock(); init(); int T=read(); while(T--) solve(); /* if(debug) { end = clock(); printf("time:%.2fs\n", 1.0 * (end - beg) / CLOCKS_PER_SEC); } */ return 0; }
F題——The Treasure of The Segments
題意可以轉換成求最少的區間不相交數(以當前區間和幾個其他區間不相交)。
這樣就好辦了,兩個區間[l1,r1]和[l2,r2]不相交的情況:r1<l2或者r2<l1.
而這兩種情況不會重複,因此我們可以直接對左端點和右端點進行排序,二分枚舉出兩種情況的答案後,把兩種情況的答案加起來維護最小值就行了。
怎麼二分呢?我們假設當前區間是[l,r]。
我們二分出所有區間中小於l的最大右端點id1(利用lower_bound實現),那麼這種情況的答案就是id1
然後再二分出所有區間中大於r的最小左端點id2(利用upper_bound實現),那麼這種情況的答案就是n-id2+1.
答案就是所有區間的id1+n-id2+1的最小值。
#include <bits/stdc++.h> #define PI atan(1.0)*4 #define rp(i,s,t) for (register int i = (s); i <= (t); i++) #define RP(i,t,s) for (register int i = (t); i >= (s); i--) #define sc(x) scanf("%d",&x) #define scl(x) scanf("%lld",&x) #define ll long long #define ull unsigned long long #define mst(a,b) memset(a,b,sizeof(a)) #define lson l,m,rt<<1 #define rson m+1,r,rt<<1|1 #define pii pair<int,int> #define pll pair<ll,ll> #define pil pair<int,ll> #define m_p make_pair #define p_b push_back #define ins insert #define era erase #define INF 0x3f3f3f3f #define LINF 0x3f3f3f3f3f3f3f3f #define dg if(debug) #define outval(a) cout << "Debuging...|" << #a << ": " << a << "\n"; using namespace std; int debug = 0; ll gcd(ll a,ll b){ return b?gcd(b,a%b):a; } ll lcm(ll a,ll b){ return a/gcd(a,b)*b; } inline int read(){ int s=0,f=1; char ch=getchar(); while(ch<'0'||ch>'9'){ if(ch=='-') f=-1; ch=getchar(); } while(ch>='0'&&ch<='9'){ s=s*10+ch-'0'; ch=getchar(); } return s*f; } const int N = 2e5+7; struct node{ int l,r; }p[N]; struct edge{ int x,type; }; vector<int> data; vector<int> L,R; void init() { data.clear();L.clear();R.clear();} void Ins(int val) { data.push_back(val); } void doit() { sort(data.begin(), data.end()); data.erase(unique(data.begin(), data.end()), data.end()); } int g(int val) { return lower_bound(data.begin(), data.end(), val) - data.begin() + 1; } void solve(){ int n=read(); init(); rp(i,1,n) p[i].l=read(),p[i].r=read(),Ins(p[i].l),Ins(p[i].r); doit(); rp(i,1,n) p[i].l=g(p[i].l),p[i].r=g(p[i].r); rp(i,1,n) L.p_b(p[i].l),R.p_b(p[i].r); int ans=n+1; sort(L.begin(),L.end()); sort(R.begin(),R.end()); rp(i,1,n){ int cur=lower_bound(R.begin(),R.end(),p[i].l)-R.begin()+1; cur--; cur+=max(0,n-(upper_bound(L.begin(),L.end(),p[i].r)-L.begin()+1)+1); ans=min(ans,cur); } cout<<ans<<endl; } int main(){ //ios::sync_with_stdio(false); cin.tie(0); cout.tie(0); #ifdef ONLINE_JUDGE #else freopen("in.txt", "r", stdin); //debug = 1; #endif time_t beg, end; //if(debug) beg = clock(); int T=read(); while(T--) solve(); /* if(debug) { end = clock(); printf("time:%.2fs\n", 1.0 * (end - beg) / CLOCKS_PER_SEC); } */ return 0; }