• 几道51nod上据说是提高组难度的dp题


    1409 加强版贪吃蛇

    听着懵逼做着傻逼。

    每个格子只能经过一次,穿过上下界答案清0,不考虑穿的话就随便dp。如果要穿就是从尽可能上面的位置穿过上界,尽可能下面的位置穿过下界。

    那么转移这一列之前找一下最上面最下面可以转移的位置。注意一下转移顺序什么的把细节写陈展就好了。

     1 //Achen
     2 #include<bits/stdc++.h>
     3 #define For(i,a,b) for(int i=(a);i<=(b);i++)
     4 #define Rep(i,a,b) for(int i=(a);i>=(b);i--)
     5 #define Formylove return 0
     6 const int N=1007;
     7 typedef long long LL;
     8 typedef double db;
     9 using namespace std;
    10 int n,m,a[N][N];
    11 LL f[N][N][2],ans;
    12 
    13 template<typename T> void read(T &x) {
    14     char ch=getchar(); x=0; T f=1;
    15     while(ch!='-'&&(ch<'0'||ch>'9')) ch=getchar();
    16     if(ch=='-') f=-1,ch=getchar();
    17     for(;ch>='0'&&ch<='9';ch=getchar()) x=x*10+ch-'0'; x*=f;
    18 }
    19 
    20 void GM(LL &x,LL y) { if(x<y) x=y; }
    21 
    22 //#define ANS
    23 int main() {
    24 #ifdef ANS
    25     freopen("1.in","r",stdin);
    26     //freopen("1.out","w",stdout);
    27 #endif
    28     read(n); read(m);
    29     For(i,1,n) For(j,1,m) read(a[i][j]);
    30     memset(f,128,sizeof(f));
    31     LL inf=f[0][0][0];
    32     For(i,1,n) if(a[i][1]!=-1) {
    33         f[i][1][0]=f[i][1][1]=a[i][1];
    34     }
    35     For(j,1,m) {
    36         int pos1=0,pos2=n+1;
    37         For(i,1,n) {
    38             if(a[i][j]==-1) break;
    39             if(f[i][j][0]!=inf) { pos1=i; break; } 
    40         }
    41         Rep(i,n,1) {
    42             if(a[i][j]==-1) break;
    43             if(f[i][j][0]!=inf) { pos2=i; break; } 
    44         }
    45         For(i,1,n) if(f[i][j][0]!=inf&&i+1<=n&&a[i+1][j]!=-1) GM(f[i+1][j][0],f[i][j][0]+a[i+1][j]);
    46         Rep(i,n,1) if(f[i][j][1]!=inf&&i-1>=1&&a[i-1][j]!=-1) GM(f[i-1][j][1],f[i][j][1]+a[i-1][j]);
    47         if(pos1&&pos1!=n&&a[n][j]!=-1) {
    48             int now=0;
    49             GM(f[n][j][1],a[n][j]);
    50             Rep(i,n-1,pos1+1) {
    51                 if(a[i][j]!=-1) { now+=a[i][j]; GM(f[i][j][1],now); }
    52                 else break;
    53             }
    54         }
    55         if(pos2!=n+1&&pos2!=1&&a[1][j]!=-1) {
    56             int now=0;
    57             GM(f[1][j][0],a[1][j]);
    58             For(i,2,pos2-1) {
    59                 if(a[i][j]!=-1) { now+=a[i][j]; GM(f[i][j][0],now); }
    60                 else break;
    61             }
    62         }
    63         For(i,1,n) {
    64             if(f[i][j][0]!=inf&&j+1<=m&&a[i][j+1]!=-1) {
    65                 GM(f[i][j+1][0],f[i][j][0]+a[i][j+1]);
    66                 GM(f[i][j+1][1],f[i][j][0]+a[i][j+1]);
    67             }
    68             if(f[i][j][1]!=inf&&j+1<=m&&a[i][j+1]!=-1) {
    69                 GM(f[i][j+1][0],f[i][j][1]+a[i][j+1]);
    70                 GM(f[i][j+1][1],f[i][j][1]+a[i][j+1]);
    71             }
    72         }
    73     }
    74     /*For(i,1,n) {
    75         For(j,1,m) {
    76             LL a=f[i][j][0],b=f[i][j][1];
    77             if(a==inf) a=0; if(b==inf) b=0;
    78             printf("%lld(%lld) ",a,b);
    79         }
    80         puts("");    
    81     }*/
    82     For(i,1,n) For(j,0,1) GM(ans,f[i][m][j]);
    83     if(!ans) ans=-1;
    84     printf("%lld
    ",ans);
    85     Formylove;
    86 }
    View Code

    1780 完美序列

    发现完美序列满足条件每次从当前完美序列去掉权值最大的数仍是完美序列。那么按权值从小到大往序列里放数,每次只能在两个比当前数小1的数之间或者序列前后放进一段当前数。

    f[i][j][0/1/2]表示放到第i大的数,有j对连续的第i-1大数,序列前后有多少第i-1大数时的方案数。

    转移用组合数转移,$sum _i j=n$ 所以时间复杂度是n*100的

     1 //Achen
     2 #include<bits/stdc++.h>
     3 #define For(i,a,b) for(int i=(a);i<=(b);i++)
     4 #define Rep(i,a,b) for(int i=(a);i>=(b);i--)
     5 #define Formylove return 0
     6 const int N=30007,p=1000000007;
     7 typedef long long LL;
     8 typedef double db;
     9 using namespace std;
    10 int n,a[N],cnt[N],mi,mx;
    11 LL C[107][107],f[N][107][3],ans;
    12 
    13 template<typename T> void read(T &x) {
    14     char ch=getchar(); x=0; T f=1;
    15     while(ch!='-'&&(ch<'0'||ch>'9')) ch=getchar();
    16     if(ch=='-') f=-1,ch=getchar();
    17     for(;ch>='0'&&ch<='9';ch=getchar()) x=x*10+ch-'0'; x*=f;
    18 }
    19 
    20 //#define ANS
    21 int main() {
    22 #ifdef ANS
    23     freopen("1.in","r",stdin);
    24     //freopen("1.out","w",stdout);
    25 #endif
    26     read(n);
    27     For(i,0,100) C[i][0]=1;
    28     For(i,1,100) For(j,1,i) C[i][j]=(C[i-1][j]+C[i-1][j-1])%p; 
    29     For(i,1,n) {
    30         read(a[i]); 
    31         if(i==1) mi=a[i],mx=a[i];
    32         else {
    33             mi=min(a[i],mi);
    34             mx=max(a[i],mx); 
    35         }
    36     }
    37     For(i,1,n) {
    38         a[i]=a[i]-mi+1;
    39         if(a[i]<=n) cnt[a[i]]++;
    40     }
    41     n=mx-mi+1;
    42     For(i,1,n) if(!cnt[i]) {
    43         puts("0");
    44         return 0;
    45     }
    46     f[1][cnt[1]-1][2]=1;
    47     For(i,2,n) For(j,0,cnt[i-1]) For(k,1,cnt[i]) {
    48         (f[i][cnt[i]-k][0]+=(f[i-1][j][0]+f[i-1][j][1]+f[i-1][j][2])%p*C[j][k]%p*C[cnt[i]-1][k-1]%p)%=p;
    49         if(k>=1&&j+1>=k) 
    50             (f[i][cnt[i]-k][1]+=(f[i-1][j][1]+f[i-1][j][2]*2)%p*C[j][k-1]%p*C[cnt[i]-1][k-1]%p)%=p;
    51         if(k>=2&&j+2>=k)
    52             (f[i][cnt[i]-k][2]+=f[i-1][j][2]*C[j][k-2]%p*C[cnt[i]-1][k-1]%p)%=p;
    53     }
    54     For(i,0,cnt[n]) ans=(ans+f[n][i][0]+f[n][i][1]+f[n][i][2])%p;
    55     printf("%lld
    ",ans);
    56     Formylove;
    57 }
    View Code

    1597 有限背包计数问题

    按容积分为小于sqrt(n)的和大于sqrt(n)的两部分。小于根号的直接按余数分类单调队列优化多重背包地做。大于根号的因为选不到根号个,相当于没有数量限制的完全背包,用划分数的奥妙重重的方法优化。f[i][s]表示用i个数凑出s的方案数,

    g[i][s]=g[i-1][s-(m+1)]+g[i-1][s-i];

    也就是要么放进一个最小数,要么所有数+1。

    因为发现把一种划分方法按数的大小排序,如

    2 2 3 3 3 4 5 5 5 5 6 7 7 7

    可以和上面两种操作的组合形成一一对应关系。

     1 //Achen
     2 #include<bits/stdc++.h>
     3 #define For(i,a,b) for(int i=(a);i<=(b);i++)
     4 #define Rep(i,a,b) for(int i=(a);i>=(b);i--)
     5 #define Formylove return 0
     6 const int N=1e5+7,p=23333333;
     7 typedef long long LL;
     8 typedef double db;
     9 using namespace std;
    10 int n,m,of,og,f[2][N],g[2][N],ans;
    11 
    12 template<typename T> void read(T &x) {
    13     char ch=getchar(); x=0; T f=1;
    14     while(ch!='-'&&(ch<'0'||ch>'9')) ch=getchar();
    15     if(ch=='-') f=-1,ch=getchar();
    16     for(;ch>='0'&&ch<='9';ch=getchar()) x=x*10+ch-'0'; x*=f;
    17 }
    18 
    19 int mo(int x) { return x>=p?x-p:(x<0?x+p:x); }
    20 
    21 //#define ANS
    22 int main() {
    23 #ifdef ANS
    24     freopen("1.in","r",stdin);
    25     //freopen("1.out","w",stdout);
    26 #endif
    27     read(n);
    28     m=sqrt(n);
    29     f[of][0]=1;
    30     For(i,1,m) {
    31         of^=1;
    32         For(w,0,i-1) {
    33             int pr=0,sum=0;
    34             for(int j=0;(LL)j*i+w<=n;j++) {
    35                 while(j-pr>i) {
    36                     sum=mo(sum-f[of^1][pr*i+w]); pr++;
    37                 } 
    38                 f[of][j*i+w]=mo(f[of^1][j*i+w]+sum);
    39                 sum=mo(sum+f[of^1][j*i+w]);
    40             }
    41         }
    42     }
    43     g[og][0]=1;
    44     ans=f[of][n];
    45     For(i,1,m) {
    46         og^=1; g[og][0]=0;
    47         For(s,1,n) 
    48             g[og][s]=mo((s-m-1>=0?g[og^1][s-(m+1)]:0)+(s-i>=0?g[og][s-i]:0));
    49         For(s,0,n) 
    50             ans=mo(ans+(LL)f[of][s]*g[og][n-s]%p);
    51     }
    52     printf("%d
    ",ans);
    53     Formylove;
    54 }
    View Code

    1849 Clarke and package

    答案就是每个物品有贡献的概率乘上价值,对每个物品单独考虑。f[i][j]表示其余的i个物品中选了j个比当前物品大的物品的概率,n^4dp即可。

     1 //Achen
     2 #include<bits/stdc++.h>
     3 #define For(i,a,b) for(int i=(a);i<=(b);i++)
     4 #define Rep(i,a,b) for(int i=(a);i>=(b);i--)
     5 #define Formylove return 0
     6 const int N=55;
     7 typedef long long LL;
     8 typedef double db;
     9 using namespace std;
    10 int n,m,k[N],c[N][N];
    11 db p[N][N],f[N][N],ans;
    12 
    13 template<typename T> void read(T &x) {
    14     char ch=getchar(); x=0; T f=1;
    15     while(ch!='-'&&(ch<'0'||ch>'9')) ch=getchar();
    16     if(ch=='-') f=-1,ch=getchar();
    17     for(;ch>='0'&&ch<='9';ch=getchar()) x=x*10+ch-'0'; x*=f;
    18 }
    19 
    20 //#define ANS
    21 int main() {
    22 #ifdef ANS
    23     freopen("1.in","r",stdin);
    24     //freopen("1.out","w",stdout);
    25 #endif
    26     read(n); read(m); m=min(n,m);
    27     For(i,1,n) {
    28         read(k[i]);
    29         For(j,1,k[i]) {
    30             read(c[i][j]);
    31             read(p[i][j]);
    32             p[i][j]/=10000.0;
    33         }        
    34     }
    35     For(a,1,n) For(b,1,k[a]) {
    36         memset(f,0,sizeof(f));
    37         f[0][0]=1.0; int o=0;
    38         For(i,1,n) if(i!=a) {
    39             o++;
    40             db p1=0,p2=0;
    41             For(j,1,k[i]) {
    42                 if(c[i][j]<c[a][b]||(c[i][j]==c[a][b]&&i<a)) p1+=p[i][j];
    43                 else p2+=p[i][j];
    44             }
    45             For(j,0,o) f[o][j]=f[o-1][j]*p1+(j?f[o-1][j-1]*p2:0);
    46         }
    47         db tp=0;
    48         For(i,0,m-1) tp+=f[o][i];
    49         ans+=p[a][b]*tp*c[a][b];
    50     }
    51     printf("%lf
    ",ans);
    52     Formylove;
    53 }
    View Code
  • 相关阅读:
    Python入门-函数进阶
    Python入门-初始函数
    Leetcode300. Longest Increasing Subsequence最长上升子序列
    Leetcode139. Word Break单词拆分
    Leetcode279. Perfect Squares完全平方数
    Leetcode319. Bulb Switcher灯泡开关
    Leetcode322. Coin Change零钱兑换
    二叉树三种遍历两种方法(递归和迭代)
    Leetcode145. Binary Tree Postorder Traversal二叉树的后序遍历
    Leetcode515. Find Largest Value in Each Tree Row在每个树行中找最大值
  • 原文地址:https://www.cnblogs.com/Achenchen/p/9788509.html
Copyright © 2020-2023  润新知