A. Toda 2
按題意模擬即可。
#include <bits/stdc++.h> using namespace std ; typedef pair < int , int > pii ; #define clr( a , x ) memset ( a , x , sizeof a ) const int MAXN = 105 ; pii a[MAXN] ; int G[MAXN * MAXN][MAXN] ; int n , x ; void solve () { int minv = MAXN ; clr ( G , 0 ) ; for ( int i = 1 ; i <= n ; ++ i ) { scanf ( "%d" , &x ) ; a[i] = pii ( x , i ) ; } int cnt = 0 ; while ( 1 ) { sort ( a + 1 , a + n + 1 ) ; if ( a[1].first == a[n].first ) break ; int m = 0 ; ++ cnt ; for ( int i = 1 ; i <= n ; ++ i ) { if ( a[i].first > a[1].first ) ++ m ; } if ( m > 1 && m <= 5 && a[n].first - 1 == a[1].first ) { for ( int i = n - m + 1 ; i <= n ; ++ i ) { a[i].first -- ; G[cnt][a[i].second] = 1 ; } break ; } else { if ( a[n].first ) a[n].first -- ; if ( a[n - 1].first ) a[n - 1].first -- ; G[cnt][a[n].second] = G[cnt][a[n - 1].second] = 1 ; } } printf ( "%d\n" , a[1].first ) ; printf ( "%d\n" , cnt ) ; for ( int i = 1 ; i <= cnt ; ++ i ) { for ( int j = 1 ; j <= n ; ++ j ) { printf ( "%d" , G[i][j] ) ; } puts ( "" ) ; } } int main () { while ( ~scanf ( "%d" , &n ) ) solve () ; return 0 ; }
B. Minimum and Maximum
首先將1和2,3和4,5和6,...兩兩比較,得到較大值和較小值,再在這$\lceil\frac{n}{2}\rceil$對中大的比大的,小的比小的即可。
#include <bits/stdc++.h> using namespace std ; typedef pair < int , int > pii ; #define clr( a , x ) memset ( a , x , sizeof a ) const int MAXN = 105 ; pii a[MAXN] ; void solve () { int cnt = 0 , n ; scanf ( "%d" , &n ) ; for ( int i = 1 ; i < n ; i += 2 ) { printf ( "? %d %d\n" , i , i + 1 ) ; fflush ( stdout ) ; char op[5] ; scanf ( "%s" , op ) ; if ( op[0] == '<' ) a[++ cnt] = pii ( i , i + 1 ) ; else a[++ cnt] = pii ( i + 1 , i ) ; } if ( n & 1 ) a[++ cnt] = pii ( n , n ) ; for ( int i = 1 ; i < cnt ; ++ i ) { printf ( "? %d %d\n" , a[i].first , a[i + 1].first ) ; fflush ( stdout ) ; char op[5] ; scanf ( "%s" , op ) ; if ( op[0] == '<' ) a[i + 1].first = a[i].first ; printf ( "? %d %d\n" , a[i].second , a[i + 1].second ) ; fflush ( stdout ) ; scanf ( "%s" , op ) ; if ( op[0] == '>' ) a[i + 1].second = a[i].second ; } printf ( "! %d %d\n" , a[cnt].first , a[cnt].second ) ; fflush ( stdout ) ; } int main () { int T ; scanf ( "%d" , &T ) ; while ( T -- ) solve () ; return 0 ; }
C. Bulmart
首先BFS求出任意兩點間的最短路,然後將物品按照單價從小到大排序。
對於每個詢問,二分答案,然後$O(w)$檢驗即可。
時間複雜度$O(n(n+m)+qw\log n)$。
#include<cstdio> #include<algorithm> using namespace std; typedef long long ll; const int N=5010; int n,m,Q,i,x,y,g[N],v[N<<1],nxt[N<<1],ed; int q[N],h,t,d[N][N]; struct P{int c,k,p;}a[N]; inline bool cmp(const P&a,const P&b){return a.p<b.p;} inline void add(int x,int y){v[++ed]=y;nxt[ed]=g[x];g[x]=ed;} inline void bfs(int S){ int i,x; for(i=1;i<=n;i++)d[S][i]=-1; q[h=t=1]=S; d[S][S]=0; while(h<=t)for(i=g[x=q[h++]];i;i=nxt[i])if(d[S][v[i]]<0)d[S][q[++t]=v[i]]=d[S][x]+1; } inline bool check(int S,int R,int M,int dis){ int t; for(int i=1;i<=m;i++)if(d[S][a[i].c]<=dis&&d[S][a[i].c]>=0){ int t=min(R,a[i].k); if(1LL*t*a[i].p>M)return 0; R-=t; M-=t*a[i].p; if(!R)return 1; } return 0; } inline int ask(){ int S,R,M; scanf("%d%d%d",&S,&R,&M); int l=0,r=n-1,mid,t=-1; while(l<=r){ mid=(l+r)>>1; if(check(S,R,M,mid))r=(t=mid)-1;else l=mid+1; } return t; } int main(){ scanf("%d%d",&n,&m); while(m--)scanf("%d%d",&x,&y),add(x,y),add(y,x); for(i=1;i<=n;i++)bfs(i); scanf("%d",&m); for(i=1;i<=m;i++)scanf("%d%d%d",&a[i].c,&a[i].k,&a[i].p); sort(a+1,a+m+1,cmp); scanf("%d",&Q); while(Q--)printf("%d\n",ask()); return 0; }
D. Running Over The Bridges
貪心,當且僅當再不嗑藥就過不了橋的時候嗑藥。
時間複雜度$O(n)$。
#include<stdio.h> #include<algorithm> #include<math.h> #include<string.h> #include<string> #include<vector> #include<set> #include<map> #include<queue> #include<time.h> #include<assert.h> #include<iostream> using namespace std; typedef long long LL; typedef pair<int,int>pi; const int LIM=100001; const int Maxn=200020; int l[Maxn],t[Maxn]; int n; LL r; vector<LL>res; LL solve(){ for(int i=1;i<=n;i++)if(l[i]>t[i])return -1; LL curt=0,rest=0,ret=0; for(int i=1;i<=n;i++){ if(rest>=l[i]){ rest-=l[i]; curt+=l[i]; continue; } l[i]-=rest;t[i]-=rest; curt+=rest; rest=0; if(t[i]>=2*l[i]){ curt+=2*l[i]; } else{ LL x=t[i]-l[i]; curt+=2*x; LL restl=l[i]-x; LL ned=restl/r; if(restl%r)ned++; ret+=ned; LL tmp=0; //printf("tmp=%lld\n",tmp); while(res.size()<LIM){ res.push_back(curt+tmp); if(tmp+r<restl)tmp+=r; else{ break; } } curt+=restl; rest=r-restl%r; if(rest==r)rest=0; } } return ret; } int main(){ while(scanf("%d%lld",&n,&r)!=EOF){ res.clear(); for(int i=1;i<=n;i++)scanf("%d",l+i); for(int i=1;i<=n;i++)scanf("%d",t+i); LL ans=solve(); if(ans<0){ puts("-1"); } else{ printf("%lld\n",ans); if(!res.size()||res.size()>LIM-1)puts(""); else{ for(int i=0;i<res.size();i++) printf("%lld%c",res[i],i==res.size()-1?'\n':' '); } } } return 0; }
E. Award Ceremony
列舉兩個隊伍,看看誰先揭榜對答案貢獻更大,即可得到拓撲序,然後模擬即可。
時間複雜度$O(n^2)$。
#include<stdio.h> #include<algorithm> #include<math.h> #include<string.h> #include<string> #include<vector> #include<set> #include<map> #include<queue> #include<time.h> #include<assert.h> #include<iostream> using namespace std; typedef long long LL; typedef pair<int,int>pi; const int Maxn=300; int n; int a[Maxn],b[Maxn]; pi V1[Maxn],V2[Maxn]; pi rev1[Maxn],rev2[Maxn]; int deg[Maxn]; vector<int>res; vector<int>G[Maxn]; int rk[Maxn],nxtrk[Maxn]; pi cur[Maxn]; void solve(){ res.clear(); for(int i=1;i<=n;i++)deg[i]=0; for(int i=1;i<=n;i++){ for(int j=0;j<G[i].size();j++)deg[G[i][j]]++; } queue<int>q; for(int i=1;i<=n;i++)if(!deg[i])q.push(i); while(!q.empty()){ int u=q.front();q.pop(); res.push_back(u); for(int i=0;i<G[u].size();i++){ int v=G[u][i]; deg[v]--; if(!deg[v])q.push(v); } } } int check(int u,int v){ int ret=0; if(rev1[u]<rev1[v]){ if(rev2[u]<rev1[v]){ if(rev2[u]<rev2[v]); else ret++; } else{ ret++; if(rev2[u]>rev2[v]); else ret++; } } else{ if(rev2[u]>rev1[v]){ if(rev2[u]>rev2[v]); else ret++; } else{ ret++; if(rev2[u]<rev2[v]); else ret++; } } return ret; } int main(){ scanf("%d",&n); for(int i=1;i<=n;i++)scanf("%d%d",a+i,b+i),b[i]+=a[i]; for(int i=1;i<=n;i++)rev1[i]=pi(-a[i],i),rev2[i]=pi(-b[i],i); for(int i=1;i<=n;i++)G[i].clear(); for(int i=1;i<=n;i++){ for(int j=i+1;j<=n;j++){ int t1=check(i,j),t2=check(j,i); if(t1!=t2){ if(t1>t2){ G[i].push_back(j); } else G[j].push_back(i); } } } solve(); for(int i=1;i<=n;i++)cur[i]=pi(-a[i],i); sort(cur+1,cur+n+1); for(int i=1;i<=n;i++){ // printf("val=%d sd=%d\n",cur[i].first,cur[i].second); rk[cur[i].second]=i; } //for(int i=1;i<=n;i++)printf("%d ",rk[i]);puts(""); int ans=0; for(int i=0;i<n;i++){ int cs=res[i]; for(int j=1;j<=n;j++)if(cur[j].second==cs)cur[j].first=-b[cs]; sort(cur+1,cur+n+1); for(int j=1;j<=n;j++)nxtrk[cur[j].second]=j; ans+=abs(nxtrk[cs]-rk[cs]); for(int j=1;j<=n;j++)rk[j]=nxtrk[j]; //printf("cs=%d ans=%d\n",cs,ans); } printf("%d\n",ans); return 0; }
F. Ber Patio
設$dp[i][j]$表示買了前$i$個物品,目前送了$j$張代金券時,最少要花多少錢,$s[i]$表示前$i$個物品的價值總和。
那麼已知$i,j,dp[i][j],s[i]$,當前手上剩餘代金券的總量等於$b+j-(s[i]-dp[i][j])$,所以不需要記錄代金券總量,列舉要用多少代金券轉移即可。
狀態數$O(\frac{n\sum a}{10})$。
時間複雜度$O(\frac{n\sum a}{4})$。
#include<stdio.h> #include<algorithm> #include<math.h> #include<string.h> #include<string> #include<vector> #include<set> #include<map> #include<queue> #include<time.h> #include<assert.h> #include<iostream> using namespace std; typedef long long LL; typedef pair<int,int>pi; const int Maxn=5050,Maxstate=10020,Inf=1e9; int n,b; int a[Maxn],sum[Maxn]; int dp[2][10020]; short pre[Maxn][Maxstate]; void init(int cs){ for(int i=0;i<Maxstate;i++)dp[cs][i]=Inf; } int main(){ scanf("%d%d",&n,&b); for(int i=1;i<=n;i++)scanf("%d",a+i),sum[i]=sum[i-1]+a[i]; int cs=0; init(0);init(1); dp[0][0]=0; for(int i=1;i<=n;i++,cs^=1){ init(cs^1); for(int j=0;j<Maxstate;j++){ if(dp[cs][j]==Inf)continue; int w=dp[cs][j]; int total=sum[i-1]; int rest=b+j-(total-w); for(int k=0;k<=rest&&k<=a[i]/2;k++){ int nw=w+a[i]-k; int nj=j+(a[i]-k)/10; if(dp[cs^1][nj]>nw){ dp[cs^1][nj]=nw; pre[i][nj]=a[i]-k; } } } } int ans=Inf,cur=-1; for(int i=0;i<Maxstate;i++)if(dp[cs][i]<ans){cur=i;ans=dp[cs][i];} printf("%d\n",ans); vector<int>rep; for(int i=n;i>0;i--){ rep.push_back(pre[i][cur]); cur=cur-pre[i][cur]/10; } reverse(rep.begin(),rep.end()); for(int i=0;i<rep.size();i++)printf("%d%c",a[i+1]-rep[i],i==rep.size()-1?'\n':' '); return 0; }
G. Car Repair Shop
按題意模擬即可。
時間複雜度$O(n^2\log n)$。
#include <bits/stdc++.h> using namespace std ; typedef pair < int , int > pii ; #define clr( a , x ) memset ( a , x , sizeof a ) const int MAXN = 10005 ; int n ; vector < pii > G ; void solve () { G.clear () ; G.push_back ( pii ( 1 , 2e9 ) ) ; for ( int i = 1 ; i <= n ; ++ i ) { sort ( G.begin () , G.end () ) ; int l , r , d , ok = 0 ; scanf ( "%d%d" , &l , &d ) ; r = l + d - 1 ; for ( int j = 0 ; j < G.size () ; ++ j ) { if ( G[j].first <= l && r <= G[j].second ) { ok = 1 ; printf ( "%d %d\n" , l , r ) ; int l1 = G[j].first , r1 = l - 1 ; int l2 = r + 1 , r2 = G[j].second ; G[j] = pii ( l1 , r1 ) ; if ( l2 <= r2 ) G.push_back ( pii ( l2 , r2 ) ) ; break ; } } if ( ok ) continue ; for ( int j = 0 ; j < G.size () ; ++ j ) { if ( G[j].second - G[j].first + 1 >= d ) { printf ( "%d %d\n" , G[j].first , G[j].first + d - 1 ) ; G[j].first += d ; break ; } } } } int main () { while ( ~scanf ( "%d" , &n ) ) solve () ; return 0 ; }
H. Delete Them
對於每一位,如果要刪的串這一位都相同,那麼就是這個字元,否則必須是'?',然後檢驗是否合法即可。
時間複雜度$O(n^2)$。
#include<cstdio> #include<cstring> const int N=200; int n,m,L,i,j,len[N],b[N],v[N];char a[N][N],s[N]; inline bool check(int x){ if(len[x]!=L)return 0; for(int i=0;i<L;i++)if(s[i]!='?'&&s[i]!=a[x][i])return 0; return 1; } int main(){ scanf("%d%d",&n,&m); for(i=1;i<=n;i++){ scanf("%s",a[i]); len[i]=strlen(a[i]); } for(i=1;i<=m;i++)scanf("%d",&b[i]),v[b[i]]=1; for(i=2;i<=m;i++)if(len[b[i]]!=len[b[1]])return puts("No"),0; L=len[b[1]]; for(i=0;i<L;i++){ s[i]=a[b[1]][i]; for(j=2;j<=m;j++)if(s[i]!=a[b[j]][i]){s[i]='?';break;} } for(i=1;i<=n;i++)if(check(i)!=v[i])return puts("No"),0; puts("Yes"); for(i=0;i<L;i++)putchar(s[i]); return 0; }
I. Olympiad in Programming and Sports
最大費用最大流裸題。
#include <bits/stdc++.h> using namespace std ; typedef pair < int , int > pii ; #define clr( a , x ) memset ( a , x , sizeof a ) const int MAXN = 20005 ; const int MAXE = 1000005 ; const int INF = 0x3f3f3f3f ; struct Edge { int v , c , w , n ; Edge () {} Edge ( int v , int c , int w , int n ) : v ( v ) , c ( c ) , w ( w ) , n ( n ) {} } ; Edge E[MAXE] ; int H[MAXN] , cntE ; int d[MAXN] , vis[MAXN] , cur[MAXN] ; int Q[MAXN] , head , tail ; int s , t ; int flow , cost ; int n , P , S ; vector < int > A , B ; void init () { cntE = 0 ; clr ( H , -1 ) ; } void addedge ( int u , int v , int c , int w ) { E[cntE] = Edge ( v , c , w , H[u] ) ; H[u] = cntE ++ ; E[cntE] = Edge ( u , 0 , -w , H[v] ) ; H[v] = cntE ++ ; } int spfa () { clr ( d , INF ) ; clr ( vis , 0 ) ; head = tail = 0 ; Q[tail ++] = s ; d[s] = 0 ; cur[s] = -1 ; while ( head != tail ) { int u = Q[head ++] ; if ( head == MAXN ) head = 0 ; vis[u] = 0 ; for ( int i = H[u] ; ~i ; i = E[i].n ) { int v = E[i].v ; if ( E[i].c && d[v] > d[u] + E[i].w ) { d[v] = d[u] + E[i].w ; cur[v] = i ; if ( !vis[v] ) { vis[v] = 1 ; Q[tail ++] = v ; if ( tail == MAXN ) tail = 0 ; } } } } if ( d[t] == INF ) return 0 ; cost += d[t] ; flow ++ ; for ( int i = cur[t] ; ~i ; i = cur[E[i ^ 1].v] ) { E[i].c -- ; E[i ^ 1].c ++ ; } return 1 ; } void solve () { init () ; s = 0 ; t = n + 2 + 1 ; int pt = n + 1 ; int st = n + 2 ; for ( int i = 1 ; i <= n ; ++ i ) { int x ; scanf ( "%d" , &x ) ; addedge ( s , i , 1 , 0 ) ; addedge ( i , pt , 1 , -x ) ; } for ( int i = 1 ; i <= n ; ++ i ) { int x ; scanf ( "%d" , &x ) ; addedge ( i , st , 1 , -x ) ; } addedge ( pt , t , P , 0 ) ; addedge ( st , t , S , 0 ) ; cost = flow = 0 ; while ( spfa () ) ; printf ( "%d\n" , -cost ) ; A.clear () ; B.clear () ; for ( int i = 1 ; i <= n ; ++ i ) { for ( int j = H[i] ; ~j ; j = E[j].n ) { int v = E[j].v ; if ( v == s ) continue ; if ( E[j].c == 0 ) { if ( v == pt ) A.push_back ( i ) ; else B.push_back ( i ) ; break ; } } } for ( int i = 0 ; i < A.size () ; ++ i ) { printf ( "%d%c" , A[i] , i < A.size () - 1 ? ' ' : '\n' ) ; } for ( int i = 0 ; i < B.size () ; ++ i ) { printf ( "%d%c" , B[i] , i < B.size () - 1 ? ' ' : '\n' ) ; } } int main () { while ( ~scanf ( "%d%d%d" , &n , &P , &S ) ) solve () ; return 0 ; }
J. Bottles
$f[i][j][k]$表示考慮了前$i$個瓶子,目前需要保留$j$個瓶子,容量總和減去被佔走的為$k$的最小代價,然後DP即可。
時間複雜度$O(n^4)$。
#include<cstdio> const int N=105,M=20005,K=10000,inf=10000000; int n,i,j,k,x,a[N],b[N],f[2][N][M]; inline void up(int&x,int y){if(x>y)x=y;} int main(){ scanf("%d",&n); for(i=1;i<=n;i++)scanf("%d",&a[i]); for(i=1;i<=n;i++)scanf("%d",&b[i]),b[i]-=a[i]; for(i=0;i<2;i++)for(j=0;j<=n;j++)for(k=0;k<M;k++)f[i][j][k]=inf; f[0][0][K]=0; for(i=x=1;i<=n;i++,x^=1){ for(j=0;j<=n;j++)for(k=0;k<M;k++)f[x][j][k]=inf; for(j=0;j<=n;j++)for(k=0;k<M;k++)if(f[x^1][j][k]<inf){ if(k+b[i]<M)up(f[x][j+1][k+b[i]],f[x^1][j][k]); if(k-a[i]>=0)up(f[x][j][k-a[i]],f[x^1][j][k]+a[i]); } } for(i=0;i<=n;i++){ int now=inf; for(j=K;j<M;j++)if(f[x^1][i][j]<inf)up(now,f[x^1][i][j]); if(now<inf)return printf("%d %d",i,now),0; } }
K. Roads Orientation Problem
留坑。
L. Expression Queries
看上去是很難寫的模擬+倍增。
留坑。
總結:
- A題poursoul沒想清楚就上去寫,導致錯誤2發,浪費了半小時機時,對於水題也應該準備充分。
- D題_ilovelife讀錯輸出格式,導致產生無效罰時,下次應注意。