Codeforce 水题报告(2)
又水了一發(fā)Codeforce ,這次繼續(xù)發(fā)發(fā)題解順便給自己PKUSC攢攢人品吧
CodeForces 438C:The Child and Polygon:
描述:給出一個(gè)多邊形,求三角剖分的方案數(shù)(n<=200)。
首先很明顯可能是區(qū)間dp,我們可以記f[i][j]為從i到j(luò)的這個(gè)多邊形的三角剖分?jǐn)?shù),那么f[i][j]=f[i][k]*f[j][k]*(i,j,k是否為1個(gè)合格的三角形)
Code:
1 #include<cstdio> 2 #include<iostream> 3 #include<cstring> 4 #include<algorithm> 5 using namespace std; 6 typedef pair<double,double> ii; 7 #define fi first 8 #define se second 9 #define maxn 410 10 #define mod 1000000007 11 int f[maxn][maxn],n; 12 ii a[maxn]; 13 inline double cross(ii x,ii y,ii z) { 14 return (y.fi-x.fi)*(z.se-x.se)-(y.se-x.se)*(z.fi-x.fi); 15 } 16 inline bool check() { 17 double ans=0; 18 for (int i=2;i<=n;i++) ans+=cross(a[1],a[i-1],a[i]); 19 return ans>0; 20 } 21 inline void revice(){ 22 for (int i=1,j=n;i<j;i++,j--) swap(a[i],a[j]); 23 } 24 int main(){ 25 scanf("%d",&n); 26 for (int i=1;i<=n;i++) scanf("%lf%lf",&a[i].fi,&a[i].se); 27 if (check()) revice(); 28 for (int i=1;i+1<=n;i++) f[i][i+1]=1; 29 for (int l=1;l<=n-1;l++) 30 for (int i=1;i+l<=n;i++) 31 for (int j=i+1;j<i+l;j++) 32 (f[i][i+l]+=f[i][j]*1ll*f[j][i+l]%mod*(cross(a[i],a[j],a[i+l])<0?1:0))%=mod; 33 printf("%d\n",f[1][n]); 34 return 0; 35 } View CodeCodeForces 438D:The Child and Sequence
描述:給一個(gè)序列,要求支持區(qū)間取模,區(qū)間求和,單點(diǎn)修改(n<=10^5)
考慮如何用線段樹來搞這個(gè)東西,很明顯對(duì)于所有區(qū)間取模操作都必須用搞到點(diǎn),但是如果我們加入一個(gè)小優(yōu)化(只有區(qū)間序列的最大值大于那個(gè)區(qū)間的話,才往下傳遞)然后我們就可以解決這個(gè)問題啦。
為啥?我們可以發(fā)現(xiàn)當(dāng)一個(gè)數(shù)取模的時(shí)候至少變小一半,因此每個(gè)數(shù)最多取模log a[i]次,所以總的時(shí)間復(fù)雜度為n log^2 n
Code:
1 #include<cstdio> 2 #include<iostream> 3 #include<cstring> 4 #include<algorithm> 5 using namespace std; 6 #define maxn 101000 7 typedef long long ll; 8 struct node { 9 int l,r,lz,mx;bool b;ll s; 10 }t[maxn*8]; 11 int a[maxn]; 12 #define lc (x<<1) 13 #define rc (lc^1) 14 #define mid ((l+r)>>1) 15 inline void update(int x){ 16 t[x].s=t[lc].s+t[rc].s; 17 t[x].mx=max(t[lc].mx,t[rc].mx); 18 t[x].b=t[lc].b&t[rc].b; 19 } 20 inline void pb(int x) { 21 if (!t[x].lz) return ; 22 if (t[x].l==t[x].r) { 23 t[x].b=1;t[x].lz=0;return ; 24 } 25 pb(lc);pb(rc); 26 if (t[lc].mx>=t[x].lz) { 27 t[lc].mx%=t[x].lz; 28 t[lc].lz=t[x].lz; 29 t[lc].s%=t[x].lz; 30 t[lc].b=0; 31 }if (t[rc].mx>=t[x].lz) { 32 t[rc].mx%=t[x].lz; 33 t[rc].lz=t[x].lz; 34 t[rc].s%=t[x].lz; 35 t[rc].b=0; 36 } 37 t[x].lz=0; 38 update(x); 39 } 40 void build(int x,int l,int r) { 41 t[x].l=l,t[x].r=r; 42 t[x].lz=0;t[x].b=1; 43 if (l==r) {t[x].s=t[x].mx=a[l];return ;} 44 build(lc,l,mid);build(rc,mid+1,r); 45 update(x); 46 } 47 ll sum(int x,int x1,int y1) { 48 int l=t[x].l,r=t[x].r; 49 if (y1<l||x1>r) return 0; 50 // pb(x); 51 if (x1<=l&&r<=y1) return t[x].s; 52 ll ans=sum(lc,x1,y1)+sum(rc,x1,y1); 53 update(x); 54 return ans; 55 } 56 void set(int x,int y,int z){ 57 int l=t[x].l,r=t[x].r; 58 if (l>y||r<y) return; 59 if (l==r) {t[x].s=t[x].mx=z;return ;} 60 // pb(x); 61 set(lc,y,z);set(rc,y,z); 62 update(x); 63 } 64 void mod(int x,int x1,int y1,int z){ 65 int l=t[x].l,r=t[x].r; 66 if (y1<l||x1>r) return ; 67 // pb(x); 68 if (t[x].mx<z) return ; 69 if (l==r) { 70 t[x].mx%=z;t[x].s%=z;return ; 71 } 72 mod(lc,x1,y1,z);mod(rc,x1,y1,z); 73 update(x); 74 } 75 int main(){ 76 int n,m; 77 scanf("%d%d",&n,&m); 78 for (int i=1;i<=n;i++) scanf("%d",a+i); 79 build(1,1,n); 80 while (m--) { 81 int opt,l,r,x,y; 82 scanf("%d",&opt); 83 switch(opt) { 84 case 1: 85 scanf("%d%d",&l,&r); 86 printf("%I64d\n",sum(1,l,r)); 87 break; 88 case 2: 89 scanf("%d%d%d",&l,&r,&x); 90 mod(1,l,r,x); 91 break; 92 case 3: 93 scanf("%d%d",&x,&y); 94 set(1,x,y); 95 break; 96 } 97 } 98 return 0; 99 } View CodeCodeForces 434D:Nanami's Power Plant
描述:有n個(gè)節(jié)點(diǎn),每個(gè)節(jié)點(diǎn)可以取一個(gè)xi(li<=xi<=ri)xi為整數(shù),然后對(duì)于每個(gè)節(jié)點(diǎn)的權(quán)值為ai*x^2+bi*x同時(shí)需要滿足某些xu-xv<=w的限制
既然是整數(shù)那么我們就可以直接用網(wǎng)絡(luò)流啦,對(duì)每個(gè)節(jié)點(diǎn)的每個(gè)取值拆下,然后連邊權(quán)為權(quán)值的邊,然后就是最小割啦。接下來再考慮那些限制的條件,我們可以對(duì)所有相鄰的東西可以直接連一個(gè)x[u]->x[v]+w,流量為inf的邊,就可以限制到啦
Code:
1 #include<cstdio> 2 #include<iostream> 3 #include<cstring> 4 #include<algorithm> 5 using namespace std; 6 #define maxn 15100 7 #define maxm 250000 8 struct edges{ 9 int to,next,cap; 10 }edge[maxm*2]; 11 int next[maxn],L,Cnt; 12 #define inf 0x7fffffff 13 inline void addedge(int x,int y,int z){ 14 L++; 15 edge[L*2]=(edges){y,next[x],z};next[x]=L*2; 16 edge[L*2+1]=(edges){x,next[y],0};next[y]=L*2+1; 17 } 18 int h[maxn],gap[maxn],p[maxn],s,t; 19 int sap(int u,int flow){ 20 if (u==t) return flow; 21 int cnt=0; 22 for (int i=p[u];i;i=edge[i].next) 23 if (edge[i].cap&&h[edge[i].to]+1==h[u]) { 24 int cur=sap(edge[i].to,min(flow-cnt,edge[i].cap)); 25 edge[i].cap-=cur;edge[i^1].cap+=cur; 26 p[u]=i; 27 if ((cnt+=cur)==flow) return flow; 28 } 29 if (!(--gap[h[u]])) h[s]=Cnt; 30 gap[++h[u]]++;p[u]=next[u]; 31 return cnt; 32 } 33 inline int maxflow(){ 34 for (int i=1;i<=Cnt;i++) p[i]=next[i]; 35 memset(h,0,sizeof(h)); 36 memset(gap,0,sizeof(gap)); 37 gap[0]=Cnt; 38 int flow=0; 39 while (h[s]<Cnt) flow+=sap(s,inf); 40 return flow; 41 } 42 #define maxk 55 43 int a[maxk],b[maxk],c[maxk],st[maxk]; 44 int l[maxk],r[maxk]; 45 inline int fun(int x,int y) {return a[x]*y*y+b[x]*y+c[x];} 46 inline int id(int x,int y) {return st[x]+y-l[x];} 47 int main(){ 48 int n,m,mx=0; 49 scanf("%d%d",&n,&m); 50 s=++Cnt,t=++Cnt; 51 for (int i=1;i<=n;i++) scanf("%d%d%d",a+i,b+i,c+i); 52 for (int i=1;i<=n;i++) { 53 scanf("%d%d",l+i,r+i); 54 st[i]=Cnt+1; 55 Cnt+=r[i]-l[i]+2; 56 for (int j=l[i];j<=r[i];j++) mx=max(mx,fun(i,j)); 57 } 58 for (int i=1;i<=n;i++) { 59 addedge(s,id(i,l[i]),inf); 60 for (int j=l[i];j<=r[i];j++) addedge(id(i,j),id(i,j+1),mx-fun(i,j)); 61 addedge(id(i,r[i]+1),t,inf); 62 } 63 while (m--) { 64 int u,v,d; 65 scanf("%d%d%d",&u,&v,&d); 66 for (int i=l[u];i<=r[u];i++) 67 if (i-d>=l[v]&&i-d<=r[v]+1) 68 addedge(id(u,i),id(v,i-d),inf); 69 } 70 printf("%d\n",mx*n-maxflow()); 71 } View CodeCodeForces 543C:Remembering Strings
描述:給定一堆字符串,改變某個(gè)字符需要一定的花費(fèi),求使所有的字符串都是好記的(存在一位的字符是該位中的唯一一個(gè))(n<=20,len<=20)
很神奇的一道題,考慮用數(shù)位dp來解決這道題。我們考慮如何使一個(gè)字符串變成好記的,很簡(jiǎn)單只要改變某一位的字符即可,或者需要把這種字符都改變的話,那么花費(fèi)是sum-mx(除了花費(fèi)最大的不變,其他都需要改變)然后就行啦
實(shí)現(xiàn)的話用了一直比較鬼畜的寫法,結(jié)果意外的短,詳情可以看代碼
Code:
1 #include<cstdio> 2 #include<iostream> 3 #include<cstring> 4 #include<algorithm> 5 #include<cstring> 6 using namespace std; 7 #define maxn 23 8 char s[23][23]; 9 int f[1<<21],a[23][23]; 10 int n; 11 inline int lowbit(int x) { 12 for (int i=0;i<n;i++) if (!((1<<i)&x)) return i; 13 } 14 int main(){ 15 int m; 16 scanf("%d%d",&n,&m); 17 for (int i=0;i<n;i++) scanf("%s",s[i]+1); 18 for (int i=0;i<n;i++) 19 for (int j=1;j<=m;j++) scanf("%d",&a[i][j]); 20 memset(f,0x3f,sizeof(f)); 21 f[0]=0; 22 for (int i=0;i<(1<<n)-1;i++) { 23 int x=lowbit(i); 24 for (int j=1;j<=m;j++) { 25 f[i|(1<<x)]=min(f[i|(1<<x)],f[i]+a[x][j]); 26 int y=0,sum=0,mx=0; 27 for (int k=0;k<n;k++) { 28 if (s[x][j]==s[k][j]) { 29 y|=1<<k; 30 sum+=a[k][j]; 31 mx=max(a[k][j],mx); 32 } 33 } 34 f[i|y]=min(f[i|y],f[i]+sum-mx); 35 } 36 } 37 printf("%d\n",f[(1<<n)-1]); 38 return 0; 39 } View CodeCodeForces 543D:Road Improvement
已知有一顆樹,對(duì)所有點(diǎn)求刪去某些邊,使得其他點(diǎn)到該點(diǎn)至多經(jīng)過一條壞邊的方案數(shù)(n<=2*10^5)
很明顯是樹形dp,那么f[x]=pai(f[ch[x]]+1)
考慮怎么從祖先的答案算出自己的答案,很明顯吧自己除去就能把祖先當(dāng)自己的子樹干了
除的時(shí)候不能直接用乘法逆元(f[x]可能為0 ), 需要存一個(gè)前綴和還有后綴和
Code:
1 #include<cstdio> 2 #include<iostream> 3 #include<cstring> 4 #include<algorithm> 5 #include<vector> 6 using namespace std; 7 typedef long long ll; 8 #define maxn 200100 9 #define mod 1000000007 10 vector<int> e[maxn]; 11 vector<ll> s[2][maxn]; 12 #define pb push_back 13 ll f[maxn],sum[maxn]; 14 int ans[maxn],fa[maxn]; 15 inline ll power(ll x,int y){ 16 ll ans=1; 17 for (;y;y>>=1) { 18 if (y&1) (ans*=x)%=mod; 19 (x*=x)%=mod; 20 } 21 return ans; 22 } 23 int q[maxn]; 24 int main(){ 25 int n; 26 scanf("%d",&n); 27 if (n==1) {printf("%d\n",0);return 0;} 28 for (int i=2;i<=n;i++) { 29 scanf("%d",fa+i); 30 e[fa[i]].pb(i); 31 } 32 q[1]=1; 33 for (int l=1,r=1,u=q[1];l<=r;u=q[++l]) { 34 for (int i=0;i<e[u].size();i++) q[++r]=e[u][i]; 35 } 36 for (int r=n,u=q[n];r;u=q[--r]) { 37 ll sum=1; 38 s[1][u].resize(e[u].size()); 39 s[0][u].resize(e[u].size()); 40 for (int i=0;i<e[u].size();i++) { 41 s[1][u][i]=sum; 42 (sum*=f[e[u][i]]+1)%=mod; 43 } 44 sum=1; 45 for (int i=e[u].size()-1;i+1;i--) { 46 s[0][u][i]=sum; 47 (sum*=f[e[u][i]]+1)%=mod; 48 } 49 f[u]=sum; 50 } 51 sum[1]=0; 52 for (int l=1,u=q[1];l<=n;u=q[++l]) { 53 ans[u]=f[u]*(sum[u]+1)%mod; 54 for (int i=0;i<e[u].size();i++) 55 sum[e[u][i]]=s[0][u][i]*s[1][u][i]%mod*(sum[u]+1)%mod; 56 } 57 for (int i=1;i<=n;i++) printf("%d ",ans[i]); 58 return 0; 59 } View CodeCodeForces 546E:Soldier and Traveling
描述:有n個(gè)城市和m條道路,每個(gè)城市有一定的士兵,士兵可以移動(dòng)到相鄰的城市,求是否存在一種移動(dòng)方式使得每個(gè)城市的駐兵數(shù)為某個(gè)值(n<=100,m<=200)
很明顯是網(wǎng)絡(luò)流吧,拆點(diǎn)然后隨便搞搞即可
Code:
1 #include<cstdio> 2 #include<iostream> 3 #include<cstring> 4 #include<algorithm> 5 using namespace std; 6 #define maxn 300 7 #define maxm 10000 8 struct edges{ 9 int to,next,cap; 10 }edge[maxm*2]; 11 int next[maxn],L,Cnt; 12 #define inf 0x7fffffff 13 inline void addedge(int x,int y,int z){ 14 L++; 15 edge[L*2]=(edges){y,next[x],z};next[x]=L*2; 16 edge[L*2+1]=(edges){x,next[y],0};next[y]=L*2+1; 17 } 18 int h[maxn],gap[maxn],p[maxn],s,t; 19 int sap(int u,int flow){ 20 if (u==t) return flow; 21 int cnt=0; 22 for (int i=p[u];i;i=edge[i].next) 23 if (edge[i].cap&&h[edge[i].to]+1==h[u]) { 24 int cur=sap(edge[i].to,min(flow-cnt,edge[i].cap)); 25 edge[i].cap-=cur;edge[i^1].cap+=cur; 26 p[u]=i; 27 if ((cnt+=cur)==flow) return flow; 28 } 29 if (!(--gap[h[u]])) h[s]=Cnt; 30 gap[++h[u]]++;p[u]=next[u]; 31 return cnt; 32 } 33 inline int maxflow(){ 34 for (int i=1;i<=Cnt;i++) p[i]=next[i]; 35 memset(h,0,sizeof(h)); 36 memset(gap,0,sizeof(gap)); 37 gap[0]=Cnt; 38 int flow=0; 39 while (h[s]<Cnt) flow+=sap(s,inf); 40 return flow; 41 } 42 #define maxk 110 43 int a[maxk][2],ans[maxk][maxk]; 44 int main(){ 45 freopen("1.in","r",stdin); 46 int n,m,sum=0,tmp=0; 47 scanf("%d%d",&n,&m); 48 s=++Cnt,t=++Cnt; 49 for (int i=1;i<=n;i++) a[i][0]=++Cnt,a[i][1]=++Cnt; 50 for (int i=1;i<=n;i++) { 51 int x; 52 scanf("%d",&x); 53 tmp+=x; 54 addedge(s,a[i][0],x); 55 } 56 for (int i=1;i<=n;i++) { 57 int x; 58 scanf("%d",&x); 59 sum+=x; 60 addedge(a[i][0],a[i][1],inf); 61 addedge(a[i][1],t,x); 62 } 63 for (int i=1;i<=m;i++) { 64 int x,y; 65 scanf("%d%d",&x,&y); 66 addedge(a[x][0],a[y][1],inf); 67 addedge(a[y][0],a[x][1],inf); 68 } 69 if (maxflow()!=sum||sum!=tmp) { 70 printf("NO\n"); 71 return 0; 72 } 73 puts("YES"); 74 for (int i=1;i<=L;i++) { 75 ans[(edge[i*2+1].to-1)>>1][(edge[i*2].to-1)>>1]=edge[i*2+1].cap; 76 } 77 for (int i=1;i<=n;i++,puts("")) 78 for (int j=1;j<=n;j++) printf("%d ",ans[i][j]); 79 return 0; 80 } View CodeCodeForces 534D:Handshakes
描述:有個(gè)房子,有n個(gè)人按順序進(jìn)去,一個(gè)人進(jìn)去就會(huì)跟房間中空閑的人握手,每3個(gè)人可以組隊(duì)做事,給定握手?jǐn)?shù),求方案
我們從0開始,每次看+1的有沒有人,沒有就-3,完了
Code:
1 #include<cstdio> 2 #include<cstring> 3 #include<cstring> 4 #include<algorithm> 5 #include<stack> 6 using namespace std; 7 #define maxn 201000 8 stack<int> s[maxn]; 9 int ans[maxn]; 10 int main(){ 11 int n,x; 12 scanf("%d",&n); 13 for (int i=1;i<=n;i++) { 14 scanf("%d",&x); 15 s[x].push(i); 16 } 17 int t=0,cnt=0; 18 while (t>=0) { 19 if (s[t].empty()) {t-=3;continue;} 20 ans[++cnt]=s[t].top();s[t].pop();t++; 21 } 22 if (cnt!=n) { 23 puts("Impossible"); 24 return 0; 25 } 26 puts("Possible"); 27 for (int i=1;i<=n;i++) printf("%d ",ans[i]); 28 return 0; 29 } View CodeCodeForces 545E:Paths and Trees
給定一個(gè)圖,求權(quán)值和最小的最短路樹
那么最短路圖建好,模擬克魯斯卡爾算法,拍個(gè)序,又由于是個(gè)有向樹,所以除了點(diǎn)u外都只有一個(gè)父親,維護(hù)這個(gè)性質(zhì)即可
CodeForces 542F:Quest
給定若干個(gè)節(jié)點(diǎn)作為二叉樹的兒子節(jié)點(diǎn),每個(gè)節(jié)點(diǎn)有其深度限制及權(quán)值,求構(gòu)建一顆二叉樹,使其權(quán)值最大
按深度限制從大到小干,每次把兩個(gè)最大的合成一個(gè)小的即可
Code:
1 #include<cstdio> 2 #include<iostream> 3 #include<cstring> 4 #include<algorithm> 5 #include<queue> 6 using namespace std; 7 #define maxn 110 8 priority_queue<int> q[maxn]; 9 int main(){ 10 int n,t,x,y; 11 freopen("1.in","r",stdin); 12 scanf("%d%d",&n,&t); 13 for (int i=1;i<=n;i++) { 14 scanf("%d%d",&x,&y); 15 q[x].push(y); 16 } 17 int ans=0; 18 for (int i=1;i<=t;i++) { 19 while (!q[i-1].empty()) { 20 int u=q[i-1].top();q[i-1].pop(); 21 if (!q[i-1].empty()) { 22 u+=q[i-1].top(); 23 q[i-1].pop(); 24 } 25 q[i].push(u); 26 } 27 if (!q[i].empty()) ans=max(ans,q[i].top()); 28 } 29 printf("%d\n",ans); 30 return 0; 31 } View Code好了就寫到這里啦,代碼回來再貼。回去收東西啦。
轉(zhuǎn)載于:https://www.cnblogs.com/New-Godess/p/4567221.html
總結(jié)
以上是生活随笔為你收集整理的Codeforce 水题报告(2)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: PHP 数组操作
- 下一篇: sql 合并相同条件的字段