标签:
又水了一发Codeforce ,这次继续发发题解顺便给自己PKUSC攒攒人品吧
CodeForces 438C:The Child and Polygon:
描述:给出一个多边形,求三角剖分的方案数(n<=200)。
首先很明显可能是区间dp,我们可以记f[i][j]为从i到j的这个多边形的三角剖分数,那么f[i][j]=f[i][k]*f[j][k]*(i,j,k是否为1个合格的三角形)
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 }
CodeForces 438D:The Child and Sequence
描述:给一个序列,要求支持区间取模,区间求和,单点修改(n<=10^5)
考虑如何用线段树来搞这个东西,很明显对于所有区间取模操作都必须用搞到点,但是如果我们加入一个小优化(只有区间序列的最大值大于那个区间的话,才往下传递)然后我们就可以解决这个问题啦。
为啥?我们可以发现当一个数取模的时候至少变小一半,因此每个数最多取模log a[i]次,所以总的时间复杂度为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 }
CodeForces 434D:Nanami‘s Power Plant
描述:有n个节点,每个节点可以取一个xi(li<=xi<=ri)xi为整数,然后对于每个节点的权值为ai*x^2+bi*x同时需要满足某些xu-xv<=w的限制
既然是整数那么我们就可以直接用网络流啦,对每个节点的每个取值拆下,然后连边权为权值的边,然后就是最小割啦。接下来再考虑那些限制的条件,我们可以对所有相邻的东西可以直接连一个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 }
CodeForces 543C:Remembering Strings
描述:给定一堆字符串,改变某个字符需要一定的花费,求使所有的字符串都是好记的(存在一位的字符是该位中的唯一一个)(n<=20,len<=20)
很神奇的一道题,考虑用数位dp来解决这道题。我们考虑如何使一个字符串变成好记的,很简单只要改变某一位的字符即可,或者需要把这种字符都改变的话,那么花费是sum-mx(除了花费最大的不变,其他都需要改变)然后就行啦
实现的话用了一直比较鬼畜的写法,结果意外的短,详情可以看代码
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 }
CodeForces 543D:Road Improvement
已知有一颗树,对所有点求删去某些边,使得其他点到该点至多经过一条坏边的方案数(n<=2*10^5)
很明显是树形dp,那么f[x]=pai(f[ch[x]]+1)
考虑怎么从祖先的答案算出自己的答案,很明显吧自己除去就能把祖先当自己的子树干了
除的时候不能直接用乘法逆元(f[x]可能为0 ), 需要存一个前缀和还有后缀和
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 }
CodeForces 546E:Soldier and Traveling
描述:有n个城市和m条道路,每个城市有一定的士兵,士兵可以移动到相邻的城市,求是否存在一种移动方式使得每个城市的驻兵数为某个值(n<=100,m<=200)
很明显是网络流吧,拆点然后随便搞搞即可
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 }
CodeForces 534D:Handshakes
描述:有个房子,有n个人按顺序进去,一个人进去就会跟房间中空闲的人握手,每3个人可以组队做事,给定握手数,求方案
我们从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 }
CodeForces 545E:Paths and Trees
给定一个图,求权值和最小的最短路树
那么最短路图建好,模拟克鲁斯卡尔算法,拍个序,又由于是个有向树,所以除了点u外都只有一个父亲,维护这个性质即可
CodeForces 542F:Quest
给定若干个节点作为二叉树的儿子节点,每个节点有其深度限制及权值,求构建一颗二叉树,使其权值最大
按深度限制从大到小干,每次把两个最大的合成一个小的即可
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 }
好了就写到这里啦,代码回来再贴。回去收东西啦。
标签:
原文地址:http://www.cnblogs.com/New-Godess/p/4567221.html