【插头dp】
〖相关资料〗
《基于连通性状态压缩的动态规划问题》 《插头DP——从不会到崩溃》
〖相关题目〗
1.【Ural1519】Formula 1
题意:给一个n×m的棋盘,其中'.'是空白,'*'是障碍,求经过所有点的哈密顿回路的数目。
分析:见资料

1 #include<cstdio> 2 #include<cstring> 3 #define LL long long 4 using namespace std; 5 const int N=15; 6 const int M=3e5+5; 7 const int hash=3e5; 8 int n,m,ex,ey,cur,pre,tot; 9 int total[2],bit[N],first[M],state[2][M]; 10 LL anss,ans[2][M]; 11 bool map[N][N]; 12 char ch; 13 struct edge{int to,next;}e[M]; 14 void ins(int now,LL num) 15 { 16 int p=now%hash; 17 for(int i=first[p];i;i=e[i].next) 18 if(state[cur][e[i].to]==now) 19 {ans[cur][e[i].to]+=num;return;} 20 total[cur]++; 21 e[++tot]=(edge){total[cur],first[p]}; 22 first[p]=tot; 23 state[cur][total[cur]]=now; 24 ans[cur][total[cur]]=num; 25 } 26 int main() 27 { 28 for(int i=1;i<=13;i++)bit[i]=i*2; 29 scanf("%d%d",&n,&m); 30 for(int i=1;i<=n;i++) 31 for(int j=1;j<=m;j++) 32 { 33 ch=getchar(); 34 while(ch!='*'&&ch!='.')ch=getchar(); 35 if(ch=='.')map[i][j]=true,ex=i,ey=j; 36 } 37 cur=0;total[cur]=1; 38 ans[cur][1]=1;state[cur][1]=0; 39 for(int i=1;i<=n;i++) 40 { 41 for(int j=1;j<=total[cur];j++)state[cur][j]*=4; 42 for(int j=1;j<=m;j++) 43 { 44 tot=0;memset(first,0,sizeof(first)); 45 pre=cur;cur^=1;total[cur]=0; 46 for(int k=1;k<=total[pre];k++) 47 { 48 int now=state[pre][k]; 49 LL num=ans[pre][k]; 50 int down=(now>>bit[j-1])%4; 51 int right=(now>>bit[j])%4; 52 if(!map[i][j]){if(!down&&!right)ins(now,num);} 53 else if(!down&&!right) 54 { 55 int nex=now+(1<<bit[j-1])+2*(1<<bit[j]); 56 if(map[i+1][j]&&map[i][j+1])ins(nex,num); 57 } 58 else if(!down&&right) 59 { 60 if(map[i][j+1])ins(now,num); 61 int nex=now-right*(1<<bit[j])+right*(1<<bit[j-1]); 62 if(map[i+1][j])ins(nex,num); 63 } 64 else if(down&&!right) 65 { 66 if(map[i+1][j])ins(now,num); 67 int nex=now-down*(1<<bit[j-1])+down*(1<<bit[j]); 68 if(map[i][j+1])ins(nex,num); 69 } 70 else if(down==1&&right==1) 71 { 72 int count=1; 73 for(int l=j+1;l<=m;l++) 74 { 75 if((now>>bit[l])%4==1)count++; 76 if((now>>bit[l])%4==2)count--; 77 if(!count) 78 { 79 int nex=now-(1<<bit[j-1])-(1<<bit[j])-(1<<bit[l]); 80 ins(nex,num);break; 81 } 82 } 83 } 84 else if(down==2&&right==2) 85 { 86 int count=1; 87 for(int l=j-2;l>=0;l--) 88 { 89 if((now>>bit[l])%4==1)count--; 90 if((now>>bit[l])%4==2)count++; 91 if(!count) 92 { 93 int nex=now-2*(1<<bit[j-1])-2*(1<<bit[j])+(1<<bit[l]); 94 ins(nex,num);break; 95 } 96 } 97 } 98 else if(down==2&&right==1) 99 { 100 int nex=now-2*(1<<bit[j-1])-(1<<bit[j]); 101 ins(nex,num); 102 } 103 else if(down==1&&right==2&&i==ex&&j==ey)anss+=num; 104 } 105 } 106 } 107 printf("%lld ",anss); 108 return 0; 109 }
2.【poj1739】Tony's Tour
题意:给一个n×m的棋盘,从左下角走到右下角,每个非障碍格子都走一遍的方法数。
分析:见资料

1 #include<cstdio> 2 #include<cstring> 3 #define LL long long 4 using namespace std; 5 const int N=15; 6 const int M=1e5+5; 7 const int hash=1e5; 8 int n,m,ex,ey,cur,pre,tot; 9 int total[2],bit[N],first[M],state[2][M]; 10 LL anss,ans[2][M]; 11 bool map[N][N]; 12 char ch; 13 struct edge{int to,next;}e[M]; 14 void init() 15 { 16 anss=0;memset(map,0,sizeof(map)); 17 for(int i=1;i<=n;i++) 18 for(int j=1;j<=m;j++) 19 { 20 ch=getchar(); 21 while(ch!='#'&&ch!='.')ch=getchar(); 22 if(ch=='.')map[i][j]=true; 23 } 24 n++;map[n][1]=map[n][m]=true; 25 n++;for(int i=1;i<=m;i++)map[n][i]=true; 26 ex=n;ey=m;cur=0;total[cur]=1; 27 ans[cur][1]=1;state[cur][1]=0; 28 } 29 void ins(int now,LL num) 30 { 31 int p=now%hash; 32 for(int i=first[p];i;i=e[i].next) 33 if(state[cur][e[i].to]==now) 34 {ans[cur][e[i].to]+=num;return;} 35 total[cur]++; 36 e[++tot]=(edge){total[cur],first[p]}; 37 first[p]=tot; 38 state[cur][total[cur]]=now; 39 ans[cur][total[cur]]=num; 40 } 41 void work() 42 { 43 for(int i=1;i<=n;i++) 44 { 45 for(int j=1;j<=total[cur];j++)state[cur][j]*=4; 46 for(int j=1;j<=m;j++) 47 { 48 tot=0;memset(first,0,sizeof(first)); 49 pre=cur;cur^=1;total[cur]=0; 50 for(int k=1;k<=total[pre];k++) 51 { 52 int now=state[pre][k]; 53 LL num=ans[pre][k]; 54 int down=(now>>bit[j-1])%4; 55 int right=(now>>bit[j])%4; 56 if(!map[i][j]){if(!down&&!right)ins(now,num);} 57 else if(!down&&!right) 58 { 59 int nex=now+(1<<bit[j-1])+2*(1<<bit[j]); 60 if(map[i+1][j]&&map[i][j+1])ins(nex,num); 61 } 62 else if(!down&&right) 63 { 64 if(map[i][j+1])ins(now,num); 65 int nex=now-right*(1<<bit[j])+right*(1<<bit[j-1]); 66 if(map[i+1][j])ins(nex,num); 67 } 68 else if(down&&!right) 69 { 70 if(map[i+1][j])ins(now,num); 71 int nex=now-down*(1<<bit[j-1])+down*(1<<bit[j]); 72 if(map[i][j+1])ins(nex,num); 73 } 74 else if(down==1&&right==1) 75 { 76 int count=1; 77 for(int l=j+1;l<=m;l++) 78 { 79 if((now>>bit[l])%4==1)count++; 80 if((now>>bit[l])%4==2)count--; 81 if(!count) 82 { 83 int nex=now-(1<<bit[j-1])-(1<<bit[j])-(1<<bit[l]); 84 ins(nex,num);break; 85 } 86 } 87 } 88 else if(down==2&&right==2) 89 { 90 int count=1; 91 for(int l=j-2;l>=0;l--) 92 { 93 if((now>>bit[l])%4==1)count--; 94 if((now>>bit[l])%4==2)count++; 95 if(!count) 96 { 97 int nex=now-2*(1<<bit[j-1])-2*(1<<bit[j])+(1<<bit[l]); 98 ins(nex,num);break; 99 } 100 } 101 } 102 else if(down==2&&right==1) 103 { 104 int nex=now-2*(1<<bit[j-1])-(1<<bit[j]); 105 ins(nex,num); 106 } 107 else if(down==1&&right==2&&i==ex&&j==ey)anss+=num; 108 } 109 } 110 } 111 printf("%lld ",anss); 112 } 113 int main() 114 { 115 for(int i=1;i<=10;i++)bit[i]=i*2; 116 scanf("%d%d",&n,&m); 117 while(n||m) 118 { 119 init();work(); 120 scanf("%d%d",&n,&m); 121 } 122 return 0; 123 }
3.【hdu1693】Eat theTrees
题意:一个棋盘上有0,1。需要找一些回路把1全部串起来,问总方法数。
分析:见资料

1 #include<cstdio> 2 #include<cstring> 3 #define LL long long 4 using namespace std; 5 const int N=15; 6 int T,n,m,p,mx,map[N][N]; 7 LL f[N][N][1<<12]; 8 int read() 9 { 10 int x=0,f=1;char c=getchar(); 11 while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();} 12 while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();} 13 return x*f; 14 } 15 int main() 16 { 17 T=p=read(); 18 while(T--) 19 { 20 memset(f,0,sizeof(f)); 21 n=read();m=read(); 22 mx=1<<(m+1); 23 for(int i=0;i<n;i++) 24 for(int j=0;j<m;j++) 25 map[i][j]=read(); 26 f[0][0][0]=1; 27 for(int i=0;i<n;i++) 28 { 29 for(int j=0;j<m;j++) 30 for(int k=0;k<mx;k++) 31 { 32 if(!f[i][j][k])continue; 33 int down=k&(1<<j),right=k&(1<<m); 34 LL num=f[i][j][k]; 35 if(!map[i][j]) 36 { 37 if(!down&&!right)f[i][j+1][k]+=num; 38 continue; 39 } 40 if(down&&right)f[i][j+1][k-(1<<j)-(1<<m)]+=num; 41 if(!down&&!right)f[i][j+1][k+(1<<j)+(1<<m)]+=num; 42 if(down&&!right) 43 { 44 f[i][j+1][k]+=num; 45 f[i][j+1][k-(1<<j)+(1<<m)]+=num; 46 } 47 if(!down&&right) 48 { 49 f[i][j+1][k]+=num; 50 f[i][j+1][k+(1<<j)-(1<<m)]+=num; 51 } 52 } 53 for(int k=0;k<mx/2;k++)f[i+1][0][k]=f[i][m][k]; 54 } 55 printf("Case %d: There are %lld ways to eat the trees. ",p-T,f[n][0][0]); 56 } 57 return 0; 58 }
4.【bzoj1187】[HNOI2007]神奇游乐园
题意:给定一个四联通的网格图,每个点有个权值,求一个长度至少为4的简单环使得环上权值和最大 。
分析:见资料

1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 #define LL long long 5 using namespace std; 6 const int N=10; 7 const int M=1e4+5; 8 const int hash=1e4; 9 int n,m,cur,pre,tot,anss,map[N*12][N]; 10 int total[2],bit[N],first[M],state[2][M],ans[2][M]; 11 struct edge{int to,next;}e[M]; 12 int read() 13 { 14 int x=0,f=1;char c=getchar(); 15 while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();} 16 while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();} 17 return x*f; 18 } 19 void ins(int now,int num) 20 { 21 int p=now%hash; 22 for(int i=first[p];i;i=e[i].next) 23 if(state[cur][e[i].to]==now) 24 {ans[cur][e[i].to]=max(ans[cur][e[i].to],num);return;} 25 total[cur]++; 26 e[++tot]=(edge){total[cur],first[p]}; 27 first[p]=tot; 28 state[cur][total[cur]]=now; 29 ans[cur][total[cur]]=num; 30 } 31 int main() 32 { 33 n=read();m=read(); 34 for(int i=1;i<=m;i++)bit[i]=i*2; 35 for(int i=1;i<=n;i++) 36 for(int j=1;j<=m;j++) 37 map[i][j]=read(); 38 cur=0;total[cur]=1; 39 ans[cur][1]=0;state[cur][1]=0; 40 anss=-0x3f3f3f3f; 41 for(int i=1;i<=n;i++) 42 { 43 for(int j=1;j<=total[cur];j++)state[cur][j]*=4; 44 for(int j=1;j<=m;j++) 45 { 46 tot=0;memset(first,0,sizeof(first)); 47 pre=cur;cur^=1;total[cur]=0; 48 for(int k=1;k<=total[pre];k++) 49 { 50 int now=state[pre][k],num=ans[pre][k]+map[i][j]; 51 int down=(now>>bit[j-1])%4,right=(now>>bit[j])%4; 52 if(!down&&!right) 53 { 54 ins(now,num-map[i][j]); 55 int nex=now+(1<<bit[j-1])+2*(1<<bit[j]); 56 if(i!=n&&j!=m)ins(nex,num); 57 } 58 else if(!down&&right) 59 { 60 if(j!=m)ins(now,num); 61 int nex=now-right*(1<<bit[j])+right*(1<<bit[j-1]); 62 if(i!=n)ins(nex,num); 63 } 64 else if(down&&!right) 65 { 66 if(i!=n)ins(now,num); 67 int nex=now-down*(1<<bit[j-1])+down*(1<<bit[j]); 68 if(j!=m)ins(nex,num); 69 } 70 else if(down==1&&right==1) 71 { 72 int count=1; 73 for(int l=j+1;l<=m;l++) 74 { 75 if((now>>bit[l])%4==1)count++; 76 if((now>>bit[l])%4==2)count--; 77 if(!count) 78 { 79 int nex=now-(1<<bit[j-1])-(1<<bit[j])-(1<<bit[l]); 80 ins(nex,num);break; 81 } 82 } 83 } 84 else if(down==2&&right==2) 85 { 86 int count=1; 87 for(int l=j-2;l>=0;l--) 88 { 89 if((now>>bit[l])%4==1)count--; 90 if((now>>bit[l])%4==2)count++; 91 if(!count) 92 { 93 int nex=now-2*(1<<bit[j-1])-2*(1<<bit[j])+(1<<bit[l]); 94 ins(nex,num);break; 95 } 96 } 97 } 98 else if(down==2&&right==1) 99 { 100 int nex=now-2*(1<<bit[j-1])-(1<<bit[j]); 101 ins(nex,num); 102 } 103 else if(down==1&&right==2&&now==(1<<bit[j-1])+2*(1<<bit[j])) 104 anss=max(anss,num); 105 } 106 } 107 } 108 printf("%d",anss); 109 return 0; 110 }
5.【bzoj2331】[SCOI2011]地板
题意:见原题
分析:公子の博客

1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 #include<iostream> 5 using namespace std; 6 const int mod=20110520; 7 const int N=15; 8 const int M=2e5+5; 9 const int hash=1e5; 10 int n,m,pre,cur,tot,anss,total[2]; 11 int bit[N],first[M],state[2][M],ans[2][M]; 12 char s[105]; 13 bool map[105][N]; 14 struct edge{int to,next;}e[M]; 15 void ins(int now,int num) 16 { 17 int p=now%hash; 18 for(int i=first[p];i;i=e[i].next) 19 if(state[cur][e[i].to]==now) 20 {ans[cur][e[i].to]=(ans[cur][e[i].to]+num)%mod;return;} 21 total[cur]++; 22 e[++tot]=(edge){total[cur],first[p]}; 23 first[p]=tot; 24 state[cur][total[cur]]=now; 25 ans[cur][total[cur]]=num; 26 } 27 void init() 28 { 29 for(int i=1;i<=10;i++)bit[i]=i*2; 30 scanf("%d%d",&n,&m); 31 if(n<m) 32 { 33 for(int i=1;i<=n;i++) 34 { 35 scanf("%s",s+1); 36 for(int j=1;j<=m;j++) 37 if(s[j]=='_')map[j][i]=true; 38 } 39 swap(n,m);return; 40 } 41 for(int i=1;i<=n;i++) 42 { 43 scanf("%s",s+1); 44 for(int j=1;j<=m;j++) 45 if(s[j]=='_')map[i][j]=true; 46 } 47 } 48 void work() 49 { 50 cur=0;total[cur]=1; 51 ans[cur][1]=1;state[cur][1]=0; 52 for(int i=1;i<=n;i++) 53 { 54 for(int j=1;j<=total[cur];j++)state[cur][j]*=4; 55 for(int j=1;j<=m;j++) 56 { 57 tot=0;memset(first,0,sizeof(first)); 58 pre=cur;cur^=1;total[cur]=0; 59 for(int k=1;k<=total[pre];k++) 60 { 61 int now=state[pre][k],num=ans[pre][k],nex; 62 int down=(now>>bit[j-1])%4; 63 int right=(now>>bit[j])%4; 64 if(down==1&&right==2)continue; 65 if(down==2&&right==1)continue; 66 if(down==2&&right==2)continue; 67 if(!map[i][j]){if(!down&&!right)ins(now,num);continue;} 68 if(!down&&!right) 69 { 70 nex=now+(1<<bit[j-1]); 71 if(map[i+1][j])ins(nex,num); 72 nex=now+(1<<bit[j]); 73 if(map[i][j+1])ins(nex,num); 74 nex=now+2*(1<<bit[j-1])+2*(1<<bit[j]); 75 if(map[i+1][j]&&map[i][j+1])ins(nex,num); 76 } 77 else if(!down&&right==1) 78 { 79 nex=now+(1<<bit[j-1])-(1<<bit[j]); 80 if(map[i+1][j])ins(nex,num); 81 nex=now+(1<<bit[j]); 82 if(map[i][j+1])ins(nex,num); 83 } 84 else if(down==1&&!right) 85 { 86 nex=now+(1<<bit[j])-(1<<bit[j-1]); 87 if(map[i][j+1])ins(nex,num); 88 nex=now+(1<<bit[j-1]); 89 if(map[i+1][j])ins(nex,num); 90 } 91 else if(!down&&right==2) 92 { 93 ins(now-2*(1<<bit[j]),num); 94 nex=now+2*(1<<bit[j-1])-2*(1<<bit[j]); 95 if(map[i+1][j])ins(nex,num); 96 } 97 else if(down==2&&!right) 98 { 99 ins(now-2*(1<<bit[j-1]),num); 100 nex=now+2*(1<<bit[j])-2*(1<<bit[j-1]); 101 if(map[i][j+1])ins(nex,num); 102 } 103 else if(down==1&&right==1) 104 { 105 nex=now-(1<<bit[j-1])-(1<<bit[j]); 106 ins(nex,num); 107 } 108 } 109 // printf("QAQ %d ",total[cur]); 110 // for(int j=1;j<=total[cur];j++) 111 // printf("[%d] %d ",state[cur][j],ans[cur][j]); 112 } 113 } 114 for(int i=first[0];i;i=e[i].next) 115 if(state[cur][e[i].to]==0) 116 {anss=ans[cur][e[i].to];break;} 117 printf("%d",anss); 118 } 119 int main() 120 { 121 init();work(); 122 return 0; 123 }
【斜率优化dp】
〖相关资料〗
〖相关题目〗
1.【bzoj1010】[HNOI2008]玩具装箱toy
题意:见原题
分析:无

1 #include<cstdio> 2 #include<algorithm> 3 #include<cstring> 4 using namespace std; 5 const int N=50050; 6 int n,L,C,c[N],q[N]; 7 long long f[N],s[N]; 8 long long read() 9 { 10 long long x=0,k=1;char c=getchar(); 11 while(c<'0'||c>'9'){if(c=='-')k=-1;c=getchar();} 12 while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();} 13 return x*k; 14 } 15 long long sum(long long x){return x*x;} 16 double slope(int j,int k){return (f[k]-f[j]+sum(s[k]+C)-sum(s[j]+C))/(2.0*(s[k]-s[j]));} 17 void dp() 18 { 19 int l=1,r=0;q[++r]=0; 20 for(int i=1;i<=n;i++) 21 { 22 while(l<r&&slope(q[l],q[l+1])<=s[i])l++; 23 int t=q[l]; 24 f[i]=f[t]+sum(s[i]-s[t]-C); 25 while(l<r&&slope(q[r-1],q[r])>slope(q[r],i))r--; 26 q[++r]=i; 27 } 28 } 29 int main() 30 { 31 n=read();L=read();C=L+1; 32 for(int i=1;i<=n;i++) 33 c[i]=read(),s[i]=s[i-1]+c[i]+1; 34 dp(); 35 printf("%lld",f[n]); 36 return 0; 37 }
2.【bzoj1911】[Apio2010]特别行动队
题意:见原题
分析:无

1 #include<cstdio> 2 #include<algorithm> 3 #include<cstring> 4 using namespace std; 5 const int N=1000050; 6 int n,a,b,c,x[N],q[N]; 7 long long s[N],f[N]; 8 long long read() 9 { 10 long long x=0,k=1;char c=getchar(); 11 while(c<'0'||c>'9'){if(c=='-')k=-1;c=getchar();} 12 while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();} 13 return x*k; 14 } 15 long long sum(long long x){return x*x;} 16 double slope(int k,int j){return (f[j]-f[k]+a*(sum(s[j])-sum(s[k]))+b*(s[k]-s[j]))/(2.0*a*(s[j]-s[k]));} 17 int main() 18 { 19 int l=0,r=0; 20 n=read();a=read();b=read();c=read(); 21 for(int i=1;i<=n;i++)x[i]=read(),s[i]=s[i-1]+x[i]; 22 for(int i=1;i<=n;i++) 23 { 24 while(l<r&&slope(q[l],q[l+1])<s[i])l++; 25 int t=q[l]; 26 f[i]=f[t]+a*sum(s[i]-s[t])+b*(s[i]-s[t])+c; 27 while(l<r&&slope(q[r],i)<slope(q[r-1],q[r]))r--; 28 q[++r]=i; 29 } 30 printf("%lld",f[n]); 31 return 0; 32 }
3.【bzoj1096】[ZJOI2007]仓库建设
题意:见原题
分析:无

1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 using namespace std; 5 const int N=1000050; 6 int n,l,r,q[N]; 7 long long f[N],x[N],p[N],c[N],num[N],sum[N]; 8 long long read() 9 { 10 long long x=0,k=1;char c=getchar(); 11 while(c<'0'||c>'9'){if(c=='-')k=-1;c=getchar();} 12 while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();} 13 return x*k; 14 } 15 double slope(int k,int j){return (f[j]-f[k]+sum[j]-sum[k])/(1.0*(num[j]-num[k]));} 16 int main() 17 { 18 n=read(); 19 for(int i=1;i<=n;i++) 20 { 21 x[i]=read();p[i]=read();c[i]=read(); 22 num[i]=num[i-1]+p[i]; 23 sum[i]=sum[i-1]+p[i]*x[i]; 24 } 25 for(int i=1;i<=n;i++) 26 { 27 while(l<r&&slope(q[l],q[l+1])<x[i])l++; 28 int t=q[l]; 29 f[i]=f[t]+(num[i]-num[t])*x[i]-(sum[i]-sum[t])+c[i]; 30 while(l<r&&slope(q[r],i)<slope(q[r-1],q[r]))r--; 31 q[++r]=i; 32 } 33 printf("%lld",f[n]); 34 return 0; 35 }
4.【bzoj3675】[Apio2014]序列分割
题意:见原题
分析:无

1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 using namespace std; 5 const int N=100050; 6 int n,k,l,r,num,a[N],q[N]; 7 long long s[N],f[N],g[N]; 8 long long read() 9 { 10 long long x=0,k=1;char c=getchar(); 11 while(c<'0'||c>'9'){if(c=='-')k=-1;c=getchar();} 12 while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();} 13 return x*k; 14 } 15 double slope(int k,int j){return (s[k]*s[k]-s[j]*s[j]+g[j]-g[k])/(1.0*s[k]-s[j]);} 16 int main() 17 { 18 n=read();k=read(); 19 for(int i=1;i<=n;i++) 20 { 21 a[i]=read(); 22 if(a[i]) 23 { 24 a[++num]=a[i]; 25 s[num]=s[num-1]+a[num]; 26 } 27 } 28 n=num; 29 for(int i=1;i<=k;i++) 30 { 31 l=1;r=0; 32 for(int j=i;j<=n;j++) 33 { 34 while(l<r&&slope(q[r],j-1)<slope(q[r-1],q[r]))r--; 35 q[++r]=j-1; 36 while(l<r&&slope(q[l],q[l+1])<s[j])l++; 37 int t=q[l]; 38 f[j]=g[t]+(s[j]-s[t])*s[t]; 39 } 40 for(int j=i;j<=n;j++)swap(f[j],g[j]); 41 } 42 printf("%lld",g[n]); 43 return 0; 44 }
5.【bzoj1597】[Usaco2008 Mar]土地购买
题意:见原题
分析:见资料

1 #include<cstdio> 2 #include<algorithm> 3 #include<cstring> 4 using namespace std; 5 const int N=50050; 6 int n,cnt,q[N]; 7 long long x[N],y[N],f[N]; 8 struct node{long long x,y;}a[N]; 9 bool cmp(node a,node b){return a.x==b.x?a.y<b.y:a.x<b.x;} 10 long long read() 11 { 12 long long x=0,f=1;char c=getchar(); 13 while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();} 14 while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();} 15 return x*f; 16 } 17 double slope(int k,int j){return (double)(f[j]-f[k])/(y[k+1]-y[j+1]);} 18 int main() 19 { 20 n=read(); 21 for(int i=1;i<=n;i++) 22 a[i].x=read(),a[i].y=read(); 23 sort(a+1,a+n+1,cmp); 24 for(int i=1;i<=n;i++) 25 { 26 while(cnt&&a[i].y>=y[cnt])cnt--; 27 x[++cnt]=a[i].x;y[cnt]=a[i].y; 28 } 29 int l=0,r=0; 30 for(int i=1;i<=n;i++) 31 { 32 while(l<r&&slope(q[l],q[l+1])<x[i])l++; 33 int t=q[l]; 34 f[i]=f[t]+y[t+1]*x[i]; 35 while(l<r&&slope(q[r-1],q[r])>slope(q[r],i))r--; 36 q[++r]=i; 37 } 38 printf("%lld",f[cnt]); 39 return 0; 40 }
6.【bzoj3156】防御准备
题意:见原题
分析:见资料

1 #include<cstdio> 2 #include<algorithm> 3 #include<cstring> 4 using namespace std; 5 const int N=1000050; 6 long long a[N],f[N],n,t,q[N],l=0,r=0; 7 long long read() 8 { 9 long long x=0,f=1;char c=getchar(); 10 while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();} 11 while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();} 12 return x*f; 13 } 14 double slope(long long k,long long j) 15 {return (2.0*(f[j]-f[k])+j*(j+1)-k*(k+1))/(2.0*(j-k));} 16 int main() 17 { 18 n=read(); 19 for(int i=1;i<=n;i++)a[i]=read(); 20 for(long long i=1;i<=n;i++) 21 { 22 while(l<r&&slope(q[l],q[l+1])<i)l++; 23 t=q[l]; 24 f[i]=f[t]+(long long)(i-t)*(i-t-1)/2+a[i]; 25 while(l<r&&slope(q[r-1],q[r])>slope(q[r],i))r--; 26 q[++r]=i; 27 } 28 printf("%lld",f[n]); 29 return 0; 30 }
7.【bzoj3437】小P的牧场
题意:见原题
分析:无

1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 using namespace std; 5 const int N=1000050; 6 long long n,a[N],b[N],sum[N],num[N],f[N],q[N],l=0,r=0; 7 int read() 8 { 9 int x=0,f=1;char c=getchar(); 10 while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();} 11 while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();} 12 return x*f; 13 } 14 double slope(long long k,long long j) 15 { 16 return (double)(f[j]-sum[j+1]+num[j+1]*n-f[k]+sum[k+1]-num[k+1]*n)/(double)(num[j+1]-num[k+1]); 17 } 18 int main() 19 { 20 n=read(); 21 for(int i=1;i<=n;i++)a[i]=read(); 22 for(int i=1;i<=n;i++)b[i]=read(); 23 for(long long i=1;i<=n;i++) 24 { 25 sum[i]=sum[i-1]+(long long)b[i-1]*(n-i+1); 26 num[i]=num[i-1]+b[i-1]; 27 } 28 for(long long i=1;i<=n;i++) 29 { 30 while(l<r&&slope(q[l],q[l+1])<i)l++; 31 long long t=q[l]; 32 f[i]=f[t]+sum[i]-sum[t+1]-(num[i]-num[t+1])*(n-i)+a[i]; 33 while(l<r&&slope(q[r],i)<slope(q[r-1],q[r]))r--; 34 q[++r]=i; 35 } 36 printf("%lld ",f[n]); 37 return 0; 38 }
【背包dp】
〖相关题目〗
1.【codeforces914H】Ember and Storm's Tree Game
题意:Zsnuoの博客
分析:Zsnuoの博客

1 #include<cstdio> 2 #include<algorithm> 3 #include<cstring> 4 #define LL long long 5 using namespace std; 6 const int N=205; 7 int n,d,mod; 8 LL ans,sum[N],c[N][N],f[N][N]; 9 int main() 10 { 11 scanf("%d%d%d",&n,&d,&mod); 12 for(int i=0;i<=n;i++)c[i][0]=1; 13 for(int i=1;i<=n;i++) 14 for(int j=1;j<=i;j++) 15 c[i][j]=(c[i-1][j]+c[i-1][j-1])%mod; 16 sum[1]=1;f[1][0]=1; 17 for(int i=2;i<=n;i++) 18 { 19 for(int j=1;j<=d;j++) 20 for(int k=1;k<i;k++) 21 f[i][j]=(f[i][j]+f[i-k][j-1]*sum[k]%mod*c[i-2][k-1]%mod)%mod; 22 for(int j=1;j<=d-1;j++) 23 sum[i]=(sum[i]+f[i][j])%mod; 24 } 25 for(int i=0;i<=n-1;i++) 26 for(int j=0;j<=d;j++) 27 for(int k=0;j+k<=d;k++) 28 if(k!=1)ans=(ans+f[i+1][j]*f[n-i][k]%mod)%mod; 29 printf("%lld",2*n*(n-1)*ans%mod); 30 return 0; 31 }
【树形dp】
〖相关题目〗
1.【SRM-05 B】无题?
题意:给定一棵树,选定一些特殊点,若点集中存在两个点有边直接相连,则将该点集计入方案,求总方案数。
分析:Zsnuoの博客

1 #include<cstdio> 2 #include<algorithm> 3 #include<cstring> 4 #define ll long long 5 using namespace std; 6 const int N=1e5+5; 7 const int mod=1e9+7; 8 int n,x,y,cnt,head[N]; 9 struct edge{int to,next;}e[N*2]; 10 ll ansn=1,dp[N][2]; 11 int read() 12 { 13 int x=0,f=1;char c=getchar(); 14 while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();} 15 while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();} 16 return x*f; 17 } 18 void ins(int u,int v){cnt++;e[cnt].to=v;e[cnt].next=head[u];head[u]=cnt;} 19 void solve(int x,int fa) 20 { 21 dp[x][1]=dp[x][0]=1; 22 for(int i=head[x];i;i=e[i].next) 23 { 24 int to=e[i].to; 25 if(to==fa)continue; 26 solve(to,x); 27 dp[x][0]=(dp[to][0]+dp[to][1])%mod*dp[x][0]%mod; 28 dp[x][1]=dp[to][0]*dp[x][1]%mod; 29 } 30 } 31 int main() 32 { 33 n=read(); 34 for(int i=1;i<n;i++) 35 { 36 x=read();y=read(); 37 ins(x,y);ins(y,x); 38 } 39 solve(1,0); 40 for(int i=1;i<=n;i++)ansn=(ansn*2)%mod; 41 printf("%lld",((ansn-dp[1][0]-dp[1][1])%mod+mod)%mod); 42 return 0; 43 }
2.【codeforces627D】Preorder Test
题意:给定一棵n个节点的无根树,求出dfs序的前k个结点权值最小值的最大值。

1 #include<cstdio> 2 #include<algorithm> 3 #include<cstring> 4 #define LL long long 5 using namespace std; 6 const int N=2e5+5; 7 int n,k,cnt,u,v; 8 int a[N],w[N],sz[N],first[N],dp[N],up[N]; 9 bool flag; 10 struct edge{int to,next;}e[N*2]; 11 int read() 12 { 13 int x=0,f=1;char c=getchar(); 14 while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();} 15 while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();} 16 return x*f; 17 } 18 void ins(int u,int v){e[++cnt]=(edge){v,first[u]};first[u]=cnt;} 19 void dfs1(int x,int fa) 20 { 21 sz[x]=1; 22 for(int i=first[x];i;i=e[i].next) 23 { 24 int to=e[i].to; 25 if(to==fa)continue; 26 dfs1(to,x);sz[x]+=sz[to];w[x]+=w[to]; 27 } 28 } 29 void dfs2(int x,int fa,int m) 30 { 31 int mx1=0,mx2=0,tot=0; 32 for(int i=first[x];i;i=e[i].next) 33 { 34 int to=e[i].to; 35 if(to==fa)continue; 36 if(w[x]-w[to]==sz[x]-sz[to]&&up[x])up[to]=1; 37 dfs2(to,x,m); 38 if(a[to]<m)continue; 39 if(sz[to]==w[to])tot+=sz[to]; 40 else 41 { 42 if(dp[to]>mx1)mx2=mx1,mx1=dp[to]; 43 else if(dp[to]>mx2)mx2=dp[to]; 44 } 45 } 46 if(a[x]<m)return; 47 if(tot+mx1+mx2+up[x]*(n-sz[x])+1>=k)flag=true; 48 dp[x]=tot+mx1+1; 49 } 50 bool check(int x) 51 { 52 memset(dp,0,sizeof(dp)); 53 memset(up,0,sizeof(up)); 54 for(int i=1;i<=n;i++)w[i]=(a[i]>=x); 55 dfs1(1,-1); 56 up[1]=1;flag=false; 57 dfs2(1,-1,x); 58 return flag; 59 } 60 int main() 61 { 62 n=read();k=read(); 63 for(int i=1;i<=n;i++)a[i]=read(); 64 for(int i=1;i<n;i++) 65 { 66 u=read();v=read(); 67 ins(u,v);ins(v,u); 68 } 69 int l=0,r=1e6,mid,ans; 70 while(l<=r) 71 { 72 mid=(l+r)>>1; 73 if(check(mid))l=mid+1,ans=mid; 74 else r=mid-1; 75 } 76 printf("%d",ans); 77 return 0; 78 }
【数位dp】
〖相关题目〗
1.【计蒜之道2017复赛E】商汤智能机器人
题意:二维平面,起点在(0,0), 假如当前在(x,y),则下一步可以走到(x+1,y+1)或(x+1,y-1)或(x+2,y),求从(0,0)走到(X,Y)的方案数。
分析:sakitsの博客

1 #include<cstdio> 2 #include<algorithm> 3 #include<cstring> 4 #define LL long long 5 using namespace std; 6 const int N=1e5+5; 7 const int mod=1e5+3; 8 LL x,y,n,tmp,na,nb; 9 int fac[N],inv[N],a[15],b[15],f[15],g[15]; 10 int power(int a,int b) 11 { 12 int ans=1; 13 while(b) 14 { 15 if(b&1)ans=1ll*ans*a%mod; 16 a=1ll*a*a%mod;b>>=1; 17 } 18 return ans; 19 } 20 int C(int n,int m){return n<m?0:1ll*fac[n]*inv[m]%mod*inv[n-m]%mod;} 21 void Mod(int& a,int b){a+=b;if(a>=mod)a-=mod;} 22 int main() 23 { 24 scanf("%lld%lld",&x,&y); 25 if((x+y)&1||x<y){printf("0");return 0;} 26 fac[0]=1; 27 for(int i=1;i<mod;i++)fac[i]=1ll*fac[i-1]*i%mod; 28 inv[mod-1]=power(fac[mod-1],mod-2); 29 for(int i=mod-1;i>=1;i--)inv[i-1]=1ll*inv[i]*i%mod; 30 n=(x+y)>>1; 31 tmp=x;while(tmp)a[++na]=tmp%mod,tmp/=mod; 32 tmp=n;while(tmp)b[++nb]=tmp%mod,tmp/=mod; 33 f[1]=1; 34 for(int i=1;i<=na;i++) 35 { 36 if(f[i]) 37 { 38 for(int j=0;j<mod;j++) 39 if(j<=a[i])Mod(f[i+1],1ll*f[i]*C(b[i],j)%mod*C(a[i]-j,b[i])%mod); 40 else Mod(g[i+1],1ll*f[i]*C(b[i],j)%mod*C(a[i]-j+mod,b[i])%mod); 41 } 42 if(g[i]) 43 { 44 for(int j=0;j<mod;j++) 45 if(j<a[i])Mod(f[i+1],1ll*g[i]*C(b[i],j)%mod*C(a[i]-j-1,b[i])%mod); 46 else Mod(g[i+1],1ll*g[i]*C(b[i],j)%mod*C(a[i]-j-1+mod,b[i])%mod); 47 } 48 } 49 printf("%d",f[na+1]); 50 return 0; 51 }