标签:欧拉图 line namespace opera 滚动 amp play 否则 clear
T1 网格
显然 n==m时,卡特兰数
n,m<=100时,滚动数组的dp
正解
ans=C(n+m,n)-C(n+m,n+1)
不会证,但是可以类比 cantelan数公式 C(2*n,n)-C(2*n,n-1)
#pragma GCC optimize("O2") #include <cstdio> #include <cstring> #include <cstdlib> #include <iostream> #include <algorithm> #define mem(a,b) memset(a,b,sizeof(a)) #define ll long long using namespace std; const int N=5006; const int LEN=20006; struct bign { int s[LEN],len; bign(){mem(s,0);len=1;} void clear(){mem(s,0);len=1;} bign operator * (const int c) { bign t=*this; int jin=0; for(int i=1;i<=t.len;++i) { t.s[i]=(t.s[i]*c+jin); jin=t.s[i]/10; t.s[i]%=10; } t.s[t.len+1]=jin; ++t.len; while(t.s[t.len]==0&&t.len>1) --t.len; while(t.s[t.len]>=10) { t.s[t.len+1]=t.s[t.len]/10; t.s[t.len]%=10; ++t.len; } return t; } bign operator / (const int c) { bign t=*this; for(int i=t.len;i>=1;--i) { t.s[i-1]+=t.s[i]%c*10; t.s[i]/=c; } while(t.s[t.len]==0&&t.len>1) --t.len; return t; } bign operator + (bign &c) { bign now=*this; //printf("yuan\n"); //now.out1(); //c.out1(); now.len=max(c.len,now.len)+1; for(int i=1;i<=now.len;++i) { now.s[i+1]+=(now.s[i]+c.s[i])/10; now.s[i]=(now.s[i]+c.s[i])%10; } while(now.s[now.len]==0&&now.len>1) --now.len; //now.out1(); return now; } bign operator - (bign &c) { bign now=*this; for(int i=1;i<=now.len;++i) { if(now.s[i]<c.s[i]) { --now.s[i+1]; now.s[i]+=10; } now.s[i]-=c.s[i]; } while(now.s[now.len]==0&&now.len>1) --now.len; return now; } void out1() { for(int i=len;i>=1;--i) printf("%d",s[i]); //printf("\n"); } }; int n,m; bign a,b,c; // C(n+m,n)-C(n+m,n+1) int main(){ scanf("%d%d",&n,&m); a.s[1]=1;b.s[1]=1; for(int i=1;i<=n;i+=2) a=a*( (n+m-i+1) * (i+1>n?1:n+m-i) ); for(int i=1;i<=n;i+=2) a=a/(i*(i+1>n?1:i+1)); for(int i=1;i<=n+1;i+=2) b=b*( (n+m-i+1) * (i+1>n+1?1:n+m-i) ); for(int i=1;i<=n+1;i+=2) b=b/(i*(i+1>n+1?1:i+1)); //a.out1(); //b.out1(); c=a-b; c.out1(); }
T2
把两个操作分开考虑,先熔断,在连接
1.对于只有一个联通快
(1)是环 ans=0
(2)是欧拉图 ans=(deg大于2的点)
(3)否则 (deg大于2的点)+(deg奇数点/2)
2.对于多个
(1)是环,直接熔断ans+1,liansum+1
(2)是欧拉图,在熔断deg>2点同时熔断成链,ans+(deg>2_sum),lainsum+1
(3)否则 ans+(deg>2_sum) liansum+(奇数点/2)
finaans=ans+liansum
#include <cstdio> #include <cstring> #include <iostream> #include <algorithm> #include <cstdlib> #define mem(a,b) memset(a,b,sizeof(a)) using namespace std; const int N=500006; struct son { int v,next; }a1[N*2]; int first[N*2],e; void addbian(int u,int v) { a1[e].v=v; a1[e].next=first[u]; first[u]=e++; } int n,m; int deg[N]; int l0[N],r0[N]; bool vis[N]; int tot,cc; void dfs1(int x) { vis[x]=1; ++cc; int temp; for(int i=first[x];i!=-1;i=a1[i].next) { temp=a1[i].v; if(vis[temp]) continue; dfs1(temp); } } int work1()// 鍙湁涓€涓仈閫氬潡 { //printf("work1\n"); int cntji=0,cntou=0,cntda=0; for(int i=1;i<=n;++i) { if(deg[i]&1) ++cntji; else ++cntou; if(deg[i]>2) ++cntda; } if(cntji==0)// 鏄鎷夊洖璺? OR 鐜? return cntda; return cntda+cntji/2;// 鍏堢啍鏂垚閾撅紝鍦ㄦ帴璧锋潵 } int sum,cntji,cntou,cntda; void dfs(int x) { vis[x]=1; ++sum; if(deg[x]&1) ++cntji; else ++cntou; if(deg[x]>2) ++cntda; int temp; for(int i=first[x];i!=-1;i=a1[i].next) { temp=a1[i].v; if(vis[temp]) continue; dfs(temp); } } int work2() { printf("work2\n"); mem(vis,0); int liansum=0,ans=0; for(int i=1;i<=m;++i) { if( vis[l0[i]]||vis[r0[i]] ) continue; sum=cntji=cntou=cntda=0; dfs( (l0[i]?l0[i]:r0[i]) ); if(cntji==0) { if(!cntda) cntda=1;//鏄竴涓幆 ans+=cntda; ++liansum; } else { ans+=cntda; liansum+=cntji/2; } } printf("ans=%d liansum=%d\n",ans,liansum); return ans+liansum; } // 鑷幆涓嶇敤鑰冭檻锛屽洜涓鸿仈閫氬揩閲屽彧鏈変竴涓嚜鐜椂锛屾寜鐓х幆绠? // 涓嶅彧鏈変竴涓嚜鐜椂锛宒eg[杩欎釜鐐筣>2锛岀啍鏂殑鏃跺€欓『渚跨啍鏂簡 int main(){ //freopen("frame4.in","r",stdin); mem(first,-1); scanf("%d%d",&n,&m); for(int i=1;i<=m;++i) { scanf("%d%d",&l0[i],&r0[i]); if(!l0[i]) l0[i]=++n; if(!r0[i]) r0[i]=++n;// 鍔犱笂鏂扮偣 ++deg[l0[i]]; ++deg[r0[i]]; addbian(l0[i],r0[i]); addbian(r0[i],l0[i]); } cc=0;tot=0; for(int i=1;i<=n;++i) if(deg[i]) ++tot; for(int i=1;i<=n;++i) if(deg[i]) { dfs1(i); break; } if(tot==cc) cout<<work1(); else cout<<work2(); }
T3
我打的不是正解,但是A了,理论复杂度过不了...
f[i][j][k] 第i个平民 j从它到根节点的状态 选了k个平民打仗
转移的时候就求出i和i-1的LCA,然后用一个t[][]数组处理出来i和i-1公共部分 各状态 选择平民打仗数量 的最优解,然后转移即可
正解是 树规 先暴搜出所有状态,再用类似dp的东西统计ans
#pragma GCC optimize("O2") #include <cstdio> #include <cstring> #include <cstdlib> #include <iostream> #include <algorithm> #define mem(a,b) memset(a,b,sizeof(a)) #define ll long long using namespace std; const int N=1106; ll inf; int n,m; int maxp,num,p[14]; ll w[N][N]; int hou[N][14],zhan[N][14]; //int lca[N][N]; ll f[2][N][N]; int now; void chu() { for(int i=1;i<=num;++i) for(int j=0;j<=maxp;++j) for(int k=1;k<n;++k) { if( (j&(1<<k)) && (j&1) ) w[i][j]+=zhan[i][k]; else if( !(j&(1<<k)) && !(j&1) ) w[i][j]+=hou[i][k]; } /*int temp,temp1,temp2; for(int i=1;i<=num;++i) for(int j=i+1;j<=num;++j) { temp=0;temp1=((1<<(n-1))-1)+i;temp2=((1<<(n-1))-1)+j; while(temp1!=temp2) { ++temp; temp1/=2; temp2/=2; } lca[i][j]=temp; }*/ } ll t[N][N]; void out11() { printf("\n"); for(int i=0;i<=maxp;++i) { for(int j=1;j<=m;++j) printf("%lld ",t[i][j]); printf("\n"); } printf("\n"); } int LCA(int x,int y) { int t1=((1<<(n-1))-1)+x,t2=((1<<(n-1))-1)+y; int cc=0; while(t1!=t2) { ++cc; t1>>=1; t2>>=1; } return cc; } void work() { mem(f,-50);inf=-f[0][0][0]; for(int i=0;i<=maxp;++i) f[0][i][i&1]=w[1][i]; int temp,temp1,nowp; int hhh; ll tt=0; now=0; for(int i=2;i<=num;++i) { now^=1; hhh=(i>m?m:i); temp=LCA(i-1,i);temp1=n-temp; for(int j=0;j<=p[temp1];++j) for(int nu=0;nu<=hhh;++nu) f[now][j][nu]=-inf; for(int j=0;j<=p[temp1];++j) { nowp=(j<<temp); for(int nu=0;nu<=hhh;++nu) { t[nowp][nu]=-inf; for(int k=0;k<=p[temp];++k) if(t[nowp][nu]<f[now^1][nowp|k][nu]) t[nowp][nu]=f[now^1][nowp|k][nu]; //t[nowp][nu]=max(t[nowp][nu],f[now^1][nowp|k][nu]); } } //out11(); for(int j=0;j<=p[temp1];++j) { nowp=j<<temp; for(int nu=0;nu<=hhh;++nu) { for(int k=0;k<=p[temp];++k) { tt=t[nowp][nu]+w[i][nowp|k]; if(f[now][nowp|k][nu+(k&1)]<tt) f[now][nowp|k][nu+(k&1)]=tt; //f[now][nowp|k][nu+(k&1)]=max(f[now][nowp|k][nu+(k&1)],t[nowp][nu]+w[i][nowp|k]); } } } } ll ans=0; for(int i=0;i<=maxp;++i) for(int j=0;j<=m;++j) if(ans<f[now][i][j]) ans=f[now][i][j]; //ans=max(ans,f[now][i][j]); cout<<ans; } //0_houqin 1_zuozhan int main(){ //freopen("T3.in","r",stdin); for(int i=1;i<=12;++i) p[i]=(1<<i)-1; scanf("%d%d",&n,&m); maxp=(1<<n)-1;num=(1<<(n-1)); for(int i=1;i<=num;++i) for(int j=1;j<n;++j) scanf("%d",&zhan[i][j]); for(int i=1;i<=num;++i) for(int j=1;j<n;++j) scanf("%d",&hou[i][j]); chu(); work(); }
标签:欧拉图 line namespace opera 滚动 amp play 否则 clear
原文地址:http://www.cnblogs.com/A-LEAF/p/7617313.html