磨合上升期,爽!
B
隊友做的
#include<bits/stdc++.h> using namespace std; #define int long long inline int read() { int x=0;bool f=1;char ch=getchar(); for(;ch<'0'||ch>'9';ch=getchar())f^=(ch=='-'); for(;ch>='0'&&ch<='9';ch=getchar())x=(x<<1)+(x<<3)+(ch^48); return f?x:-x; } const int N=105; int n,d,p,res; int h[N]; int gcd(int x,int y){ if (y==0) return x; return gcd(y,x%y); } signed main() { cin >> n >> d; for (int i=1;i<=n;i++) cin >> h[i]; p=h[n]; for (int i=1;i<n;i++) p=gcd(p,h[i]); res=d%p; if (res>p/2) res=p-res; cout << res << endl; return 0; }
L
#include<bits/stdc++.h> using namespace std; const int N=9; char ch[N+5][N+5]; void Kafka() { for(int i=1;i<=N;++i) scanf("%s",ch[i]+1); bool flag=1; for(int i=1;i<=N;putchar('\n'),++i) for(int j=1;j<=N;++j) { if(i>1&&i<N&&j>1&&j<N&&ch[i][j]=='8'&&flag) putchar('8'),flag=0; else putchar('*'); } } signed main() { Kafka(); return 0; }
J
對於這類 "每個點都是1出度,指向的點可以確定" 的題,經典做法是倍增跳
23年的杭電多校也有一道類似的,問走x步在環上走到哪裡,那題想到倍增直接做完
這題比較麻煩的地方在於要先預處理出f[i]表示i到的點才能進行倍增
預處理可以用二分/倍增實現
#include<bits/stdc++.h> using namespace std; const int N=1e5; int n,a,b; char s[N+5]; //PART 1: int sum[N+5]; pair<int,bool> f[N+5]; void Get_Prefix() { sum[1]=s[1]^48; for(int i=2;i<=n;++i) sum[i]=sum[i-1]+(s[i]^48); } inline int QueryA(int L,int R){return L<=R?sum[R]-sum[L-1]:0;} inline int QueryB(int L,int R){return L<=R?R-L+1-QueryA(L,R):0;} int check(int L,int R,int A,int B) { if(A+QueryA(L,R)>=a) return 1; else if(B+QueryB(L,R)>=a) return 0; return -1; } int check(int A,int B) { if(A>=a) return 1; else if(B>=a) return 0; return -1; } int Find_Len(int L,int R,int A,int B) { int l=1,r=R-L+1; for(int mid=l+r>>1;l<r;check(L,L+mid-1,A,B)>-1?r=mid:l=mid+1)mid=l+r>>1; return l; } int Find_Nums(int A,int B) { int l=0,r=(2*a-1)/n+1,tmpA=QueryA(1,n),tmpB=QueryB(1,n);; for(int mid=l+r+1>>1;l<r;check(A+mid*tmpA,B+mid*tmpB)>-1?r=mid-1:l=mid) mid=l+r+1>>1; return l; } void Kafka() { cin>>n>>a>>b; cin>>s+1; Get_Prefix(); // for(int i=1;i<=n;++i) printf("sum[%d]=%d\n",i,sum[i]); for(int i=1;i<=n;++i) { if(~check(i,n,0,0)) { int tmp=Find_Len(i,n,0,0); f[i]=make_pair(i+tmp,check(i,i+tmp-1,0,0)); if(f[i].first>n) f[i].first-=n; } else { int nums=Find_Nums(QueryA(i,n),QueryB(i,n)); int A=QueryA(i,n)+nums*QueryA(1,n),B=QueryB(i,n)+nums*QueryB(1,n); if(A>=a) f[i]=make_pair(1,1); else if(B>=a) f[i]=make_pair(1,0); else { int tmp=Find_Len(1,n,A,B); f[i]=make_pair(1+tmp,check(1,tmp,A,B)); if(f[i].first>n) f[i].first-=n; } } } // for(int i=1;i<=n;++i) printf("f[%d]=%d and %d\n",i,f[i].first,f[i].second); } //PART 2: const int LIMIT=18; pair<int,int> g[LIMIT+5][N+5]; int Gcheck(int A,int B) { if(A>=b) return 1; else if(B>=b) return 0; return -1; } int Ans(int x) { int A=0,B=0; for(int i=LIMIT-1;~i;--i) { int Len=1<<i,tmpA,tmpB; tmpA=g[i][x].second,tmpB=Len-tmpA; if(~Gcheck(A+tmpA,B+tmpB)) continue; x=g[i][x].first,A+=tmpA,B+=tmpB; } A+=g[0][x].second; if(A>=b) return 1; else return 0; } void Himeko() { for(int i=1;i<=n;++i) g[0][i]=f[i]; for(int i=1;i<LIMIT;++i) for(int j=1;j<=n;++j) { g[i][j].first=g[i-1][g[i-1][j].first].first; g[i][j].second=g[i-1][j].second+g[i-1][g[i-1][j].first].second; } // for(int i=0;i<LIMIT;++i) for(int j=1;j<=n;++j) printf("g[%d][%d]:%d and %d\n",i,j,g[i][j].first,g[i][j].second); for(int i=1;i<=n;++i) cout<<(char)(Ans(i)^48); } signed main() { Kafka(); Himeko(); return 0; }
A
思路一直假了,在那邊用一種求得出方案的nlog做法寫模擬,掛了兩發後實在找不到返利,開始貪心
貪心的實質就是算供給,運過去需要的最少次數S為 (n-r)/(r-l) ,能提供的總次數為 Σ min( (h[i]-1)/2, S)
Σ min( (h[i]-1)/2, S) >= S*L 即可
證明還是很妙的,數學歸納法
#include<bits/stdc++.h> using namespace std; #define int long long inline int read() { int x=0;bool f=1;char ch=getchar(); for(;ch<'0'||ch>'9';ch=getchar())f^=(ch=='-'); for(;ch>='0'&&ch<='9';ch=getchar())x=(x<<1)+(x<<3)+(ch^48); return f?x:-x; } const int N=5e5+505; int n,l,r; int h[N],d[N]; bool sol(){ if (n<l) return false; for (int i=1;i<=n;i++){ int x=(h[i]-1)/2; d[1]++; d[x+1]--; } for (int i=1;i<=n;i++) d[i]+=d[i-1]; int cnt=0,sum=0,k=r-l; for (int i=1;i+r<n+1;i+=k){ cnt++; sum+=d[cnt]; if (sum<cnt*l) return false; } return true; } signed main() { cin >> n >> l >> r; for (int i=1;i<=n;i++) h[i]=read(); if (sol()) cout << "Yes" << endl; else cout << "No" << endl; return 0; }
J
給定n塊兩端都有數字的骨牌,要求排列它們使得任意相鄰的兩端都不相等,排列時可以指定某個骨牌左右順序
本來想到了奇怪的圖論最佳化建圖去,在那邊網路流流了半天沒網出來
首先注意到如果兩端都不相等,假設有x個,那麼這x個怎麼排都可以,如果撞了反一下就好 ........①
如果兩端都相等,假設有y個,問題轉化為給定長度為y的陣列a[i](其中a[i]表示第i個數出現的次數)
每次都可以挑兩個出來對消,問要怎麼構造使得剩下的最少?
經典結論是:每次挑眾數和隨便一個數去刪,只要眾數<=sum/2,偶數能消完,奇數剩一個。否則眾數>sum/2,一定會有剩餘
實現時我用了小根堆,每次pop兩次堆頭對消
到這裡處理完了兩端都相同的,不妨假設剩下的為(1,1)
還沒用上的骨牌裡如果有(2,1) (3,1)(4,1)這種一端相同的也全部可以接上去
最後還剩兩端不一樣 && 兩端都≠1的,這就和 ① 一樣了
#include<bits/stdc++.h> using namespace std; const int N = 2e5+5; int n; inline int read() { int x=0;bool f=1;char ch=getchar(); for(;ch<'0'||ch>'9';ch=getchar())f^=(ch=='-'); for(;ch>='0'&&ch<='9';ch=getchar())x=(x<<1)+(x<<3)+(ch^48); return f?x:-x; } int xid[N<<1],tot[N<<1],x[N],y[N]; int cntx=0,flag=1; struct node{ int c,v; /* bool operator */ bool operator <(const node &b)const{return v==b.v?c<b.c:v>b.v;} bool operator >(const node &b)const{return v==b.v?c>b.c:v<b.v;} }; priority_queue<node,vector<node>,greater<node>>q; void solve(){ n=read(); for(int i=1;i<=n;i++){ x[i]=read(),y[i]=read(); xid[++cntx]=x[i]; xid[++cntx]=y[i]; } sort(xid+1,xid+1+cntx); cntx=unique(xid+1,xid+1+cntx)-(xid+1); int sum=0; vector<pair<int,int>>a; for(int i=1;i<=n;i++){ int idx=lower_bound(xid+1,xid+1+cntx,x[i])-(xid); int idy=lower_bound(xid+1,xid+1+cntx,y[i])-(xid); if(x[i]==y[i]){ tot[idx]++; } else a.push_back({idx,idy}); } int most=0,val=-1; for(int i=1;i<2*N;i++){ if(!tot[i]) continue; q.push((node){i,tot[i]}); sum+=tot[i]; if(tot[i]>most){ most=tot[i],val=i; } } int flag=0; int last=-1; vector<pair<int,int>>out; if(!most){ flag=1; for(auto v:a){ if(v.first==last){ out.push_back({v.second,v.first}); last=v.first; continue; } if(v.second==last){ out.push_back({v.first,v.second}); last=v.second; continue; } out.push_back({v.first,v.second}); last=v.second; } } else { if(most<=sum/2){ // 1.clear int left=0; flag=1; while(!q.empty()){ auto u=q.top(); q.pop(); if(q.empty()==true) { left=u.c; break; } auto v=q.top(); q.pop(); out.push_back({u.c,u.c}); out.push_back({v.c,v.c}); last=v.c; u.v--;v.v--; if(u.v) q.push(u); if(v.v) q.push(v); } if(left) { out.push_back({left,left}); last=left; } for(auto v:a){ if(v.first==last){ out.push_back({v.second,v.first}); last=v.first; continue; } if(v.second==last){ out.push_back({v.first,v.second}); last=v.second; continue; } out.push_back({v.first,v.second}); last=v.second; } } else { node tmp; while(!q.empty()){ auto u=q.top(); q.pop(); if(q.empty()==true) { tmp=u; break; } auto v=q.top(); q.pop(); out.push_back({u.c,u.c}); out.push_back({v.c,v.c}); last=v.c; u.v--;v.v--; if(u.v) q.push(u); if(v.v) q.push(v); } out.push_back({tmp.c,tmp.c}); last=tmp.c; tmp.v--; int cnt=0; for(int i=1;i<=n;i++){ if(x[i]==y[i]) continue; int idx=lower_bound(xid+1,xid+1+cntx,x[i])-(xid); int idy=lower_bound(xid+1,xid+1+cntx,y[i])-(xid); if(idx==tmp.c){ out.push_back({idy,idx}); } else if(idy==tmp.c){ out.push_back({idx,idy}); } else cnt++; } if(cnt>=tmp.v) { flag=1; for(int i=1;i<=n;i++){ if(x[i]==y[i]) continue; int idx=lower_bound(xid+1,xid+1+cntx,x[i])-(xid); int idy=lower_bound(xid+1,xid+1+cntx,y[i])-(xid); if(tmp.v&& idx!=tmp.c&&idy!=tmp.c){ out.push_back({idx,idy}); out.push_back({tmp.c,tmp.c}); last=tmp.c; tmp.v--; } else { if(idx==tmp.c || idy==tmp.c ) continue; if(idx!=last){ out.push_back({idx,idy}); last=idy; } if(idy!=last){ out.push_back({idy,idx}); last=idx; } } } } } } if(!flag){ cout<<"NO"<<"\n"; } else { cout<<"YES"<<"\n"; for(auto v:out){ cout<<xid[v.first]<<" "<<xid[v.second]<<"\n"; } } } signed main() { solve(); return 0; }