Codeforces Round #408 (Div. 2)
C. Bank Hacking
題目大意:給出一棵n個節(jié)點的樹,每個節(jié)點有一個權(quán)值,刪掉一個點的代價為當(dāng)前這個點的權(quán)值,并且會使其相鄰點和距離為2且中間隔著未被刪除的點的點權(quán)值加1,現(xiàn)在選一個點開始刪,之后每次能刪掉被刪過的點的相鄰點,問刪掉整棵樹,刪各節(jié)點花費的最大值最小是多少。(n<=300,000)
思路:確定第一個刪的點之后,與這個點相鄰的點的刪除花費是原權(quán)值加1,其他點是原權(quán)值加2,把所有點權(quán)加2后枚舉一個點減2再把相鄰的減1,線段樹統(tǒng)計答案后改回去,總復(fù)雜度O(nlogn),O(n)也能做,不是很難,這里就不說了(zkw線段樹好寫又不用考慮各種情況,這題沒有不用的道理)。
#include<cstdio> #include<cstring> #include<algorithm> using namespace std; inline int read() {int x,f=1;char c;while((c=getchar())<'0'||c>'9')if(c=='-')f=0;for(x=c-'0';(c=getchar())>='0'&&c<='9';)x=(x<<3)+(x<<1)+c-'0';return f?x:-x; } #define MN 300000 #define N 524288 struct edge{int nx,t;}e[MN*2+5]; int t[N*2+5],h[MN+5],en; inline void ins(int x,int y) {e[++en]=(edge){h[x],y};h[x]=en;e[++en]=(edge){h[y],x};h[y]=en; } void add(int k,int x){for(t[k+=N]+=x;k>>=1;)t[k]=max(t[k<<1],t[k<<1|1]);} int main() {int n=read(),i,j,ans=0x7FFFFFFF;memset(t,128,sizeof(t));for(i=1;i<=n;++i)t[i+N]=read()+2;for(i=N;--i;)t[i]=max(t[i<<1],t[i<<1|1]);for(i=1;i<n;++i)ins(read(),read());for(i=1;i<=n;++i){add(i,-2);for(j=h[i];j;j=e[j].nx)add(e[j].t,-1);ans=min(ans,t[1]);add(i,2);for(j=h[i];j;j=e[j].nx)add(e[j].t,1);}printf("%d",ans); }?
D.Police Stations
題目大意:給出一棵n個點的樹,有k個警站分布在一些點上,現(xiàn)在可以刪掉若干條邊,使得各個點到警站的最短距離不超過d,保證一開始各個點都滿足,要求輸出最多刪幾條邊并輸出方案。(n<=300,000)
思路:每個點只要能走到最近的一個警站就可以了,其他邊能刪就刪,我們從各個警站開始bfs,每個警站擴張自己的“地盤”,如果碰到別人的地盤,就把這條邊刪掉,復(fù)雜度O(n)。注意警站可能重點,很坑爹。
#include<cstdio> inline int read() {int x;char c;while((c=getchar())<'0'||c>'9');for(x=c-'0';(c=getchar())>='0'&&c<='9';)x=x*10+c-'0';return x; } #define MN 300000 struct edge{int nx,t;}e[MN*2+5]; int h[MN+5],en=1,q[MN+5],qn,u[MN+5],f[MN+5],cnt,ans[MN+5]; inline void ins(int x,int y) {e[++en]=(edge){h[x],y};h[x]=en;e[++en]=(edge){h[y],x};h[y]=en; } int main() {int n,k,d,i,j;n=read();k=read();d=read();for(i=1;i<=k;++i)u[j=read()]?0:u[q[++qn]=j]=1;for(i=1;i<n;++i)ins(read(),read());for(i=1;i<=qn;++i)for(j=h[q[i]];j;j=e[j].nx)if(e[j].t!=f[q[i]])if(u[e[j].t])ans[j>>1]?0:(++cnt,ans[j>>1]=1);else u[q[++qn]=e[j].t]=1,f[e[j].t]=q[i];printf("%d\n",cnt);for(i=1;i<n;++i)if(ans[i])printf("%d ",i); }?
E.Exam Cheating
題目大意:一個人要作弊,她旁邊坐著兩個學(xué)霸,考卷總共n題,已知兩個學(xué)霸已經(jīng)答了哪些題,這個人最多可以看p次,每次可以選一個人看最多連續(xù)的k道題(無論那人是否答了),求最多可以抄到幾道題。(n,p<=1000,k<=50)
思路:用f[i][j][x][y]表示從左到右看到第i題,已經(jīng)啟用了j次看題機會,第一個人之后還能看連續(xù)的x題,第二個人之后還能看連續(xù)的y題,轉(zhuǎn)移時如果x或y還大于0就直接看這題,使x或y減1,否則如果有一個是0,我們選擇不看這個人的這題或者新開一次看題機會并令x或y變成k-1,這樣復(fù)雜度是O(npk^2),發(fā)現(xiàn)當(dāng)p*k>=2n時我們可以直接看兩個人的所有題目,所以只要在p<2n/k時dp,那么復(fù)雜度就只有O(n*n/k*k^2)=O(n^2*k)。
#include<cstdio> #include<cstring> inline int read() {int x;char c;while((c=getchar())<'0'||c>'9');for(x=c-'0';(c=getchar())>='0'&&c<='9';)x=x*10+c-'0';return x; } #define MN 1000 #define MK 50 int a[MN+5],b[MN+5],f[2][MN+5][MK+5][MK+5]; inline void up(int&a,int b){if(b>a)a=b;} int main() {int n,p,k,i,j,x,y,nw,nx,ans=0;n=read();p=read();k=read();for(i=read();i--;)++a[read()];for(i=read();i--;)++b[read()];if(p*k>=2*n){for(i=1;i<=n;++i)if(a[i]||b[i])++ans;return 0*printf("%d",ans);}memset(f[0],128,sizeof(f[0]));f[0][0][0][0]=0;for(i=0;i<n;++i){nw=i&1;nx=nw^1;memset(f[nx],128,sizeof(f[nx]));for(j=0;j<=p;++j)for(x=0;x<k;++x)for(y=0;y<k;++y)if(f[nw][j][x][y]>=0){if(x&&y)up(f[nx][j][x-1][y-1],f[nw][j][x][y]+(a[i+1]||b[i+1]));if(!x&&y){up(f[nx][j][0][y-1],f[nw][j][x][y]+b[i+1]);if(j<p)up(f[nx][j+1][k-1][y-1],f[nw][j][x][y]+(a[i+1]||b[i+1]));}if(x&&!y){up(f[nx][j][x-1][0],f[nw][j][x][y]+a[i+1]);if(j<p)up(f[nx][j+1][x-1][k-1],f[nw][j][x][y]+(a[i+1]||b[i+1]));}if(!x&&!y){up(f[nx][j][0][0],f[nw][j][0][0]);if(j<p)up(f[nx][j+1][k-1][0],f[nw][j][x][y]+a[i+1]),up(f[nx][j+1][0][k-1],f[nw][j][x][y]+b[i+1]);if(j+1<p)up(f[nx][j+2][k-1][k-1],f[nw][j][x][y]+(a[i+1]||b[i+1]));}}}printf("%d",f[nx][p][0][0]); }?
轉(zhuǎn)載于:https://www.cnblogs.com/ditoly/p/CF408.html
創(chuàng)作挑戰(zhàn)賽新人創(chuàng)作獎勵來咯,堅持創(chuàng)作打卡瓜分現(xiàn)金大獎總結(jié)
以上是生活随笔為你收集整理的Codeforces Round #408 (Div. 2)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: JavaScript权威指南--多媒体和
- 下一篇: 已知可生成0~4的rand5(),实现生