【算法总结】动态规划相关

【插头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\n",anss);
108     return 0;
109 }
View Code

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\n",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 }
View Code

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.\n",p-T,f[n][0][0]);
56     }
57     return 0;
58 }
View Code

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 }
View Code

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\n",total[cur]);
110 //            for(int j=1;j<=total[cur];j++)
111 //                printf("[%d] %d\n",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 }
View Code

【斜率优化dp】

〖相关资料

《斜率优化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 }
View Code

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 }
View Code

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 }
View Code

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 }
View Code

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 }
View Code

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 }
View Code

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\n",f[n]);
37     return 0;
38 }
View Code

【背包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 }
View Code

【树形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 }
View Code

2.【codeforces627D】Preorder Test

题意:给定一棵n个节点的无根树,求出dfs序的前k个结点权值最小值的最大值。

分析:godspeedkakaの博客

 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 }
View Code

【数位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 }
View Code

                                                                                                                                                                                                                       

转载于:https://www.cnblogs.com/zsnuo/p/8572425.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值