zoukankan      html  css  js  c++  java
  • dp--递推

     

    Attack on Titans

     ZOJ - 3747 

    题意:有三种兵A,B,C,选n个排队,问(至少m个连续的B和至多k个连续的C)的方案数。

    理解了很长时间,,,好菜=_=||

    先贴上代码,有空来写

     1 #include <bits/stdc++.h>
     2 using namespace std;
     3 #define ll long long
     4 const int maxn = 1000010;
     5 const int mod = 1000000007;
     6 ll d[maxn][4];
     7 ll n,m,k;
     8 ll cal(int u){
     9     d[0][0]=1;
    10     d[0][1]=0;
    11     d[0][2]=0;
    12     for(int i=1;i<=n;i++){
    13         ll sum=(d[i-1][0]+d[i-1][1]+d[i-1][2])%mod;
    14         d[i][2]=sum;
    15 
    16         if(i<=u) d[i][0]=sum;
    17         else if(i==u+1) d[i][0]=(sum-1)%mod;
    18         else d[i][0]=(sum-d[i-u-1][1]-d[i-u-1][2])%mod;
    19 
    20         if(i<=k) d[i][1]=sum;
    21         else if(i==k+1) d[i][1]=(sum-1)%mod;
    22         else d[i][1]=(sum-d[i-1-k][0]-d[i-1-k][2])%mod;
    23     }
    24     return (d[n][0]+d[n][1]+d[n][2])%mod;
    25 }
    26 int main(){
    27     while(scanf("%d%d%d",&n,&m,&k)!=EOF){
    28         ll ans=cal(n);
    29         ans=((ans-cal(m-1))%mod+mod)%mod;
    30         printf("%lld
    ",ans);
    31     }
    32     return 0;
    33 }
    View Code

    Mex

     HDU - 4747

    题意:求所有区间的mex和。mex值为没有在该区间出现过的最小非负整数。

    感谢大神的分析http://blog.csdn.net/cc_again/article/details/11856847,可是对我等蒟蒻还是难以理解~~

    又想了很久才有点明白orz▄█▀█●,模拟一波~

    我们求以i结尾的区间的mex和f[i],再累加就是答案。为什么要这样求呢?因为可以从f[i-1]推出f[i]。记f[i] = f[i-1] +temp

    初始temp=0,下面求temp

    现在看求第f[i]的过程,现在数列中加入了新的数val=a[i]

    首先可以想到的是,对于上一个出现val的位置p(即代码里的last[a[i]]),p之前的元素(即f[p-1],f[p-2],…… f[1])对f[i]的结果没有任何影响(因为在a[i]之前的区间里已经有val了)

    现在考虑p到i之间的元素,可以知道,他们中可能有  因为没有val这个元素  而导致 到f[i-1]的mex是比小于等于val的,而现在加入了val,那么它的mex就会增大

    那么加入val之后都对哪些元素有影响呢?

    这里定义一个覆盖:如果j到i之间出现了0到x的所有值,那么称x的 覆盖为j。

    对于新加入的val,求出val-1的覆盖j,那么对于p(上一个val的位置)+1到  min ( j , last[val] )之间的元素,他们到a[i]=val这个位置的mex都【至少】是val+1,本来他们到a[i-1]的mex是val,即都变大了1。此时temp += min ( j , last[val] )  - p。

    上面为什么说至少呢?说明还有可能大于val+1。

    举个例子,6  4  0  2 1 5  3  。现在处理第七位3, f[7] = f[6] + temp  = 9 + temp 。

    加入3之后,根据上面的步骤,我们先求得2的覆盖是3,所以1到3的mex至少变成了4(他们在加入3之前是3),但是显然6的mex是7,4的mex是6,这一步只使得a[3]的mex值正确了。 此时temp +=3。 temp=3。

    这是因为前面已经出现了4,5,6,在加入3之前他们没有任何,加入3导致他们也有了作用。这就等价于我们又加入了4,5,6

    所以我们还要求3的覆盖,4的覆盖,5的覆盖……,直到mex值完全正确。

    步骤如下:

    加入4,last[4]=2,3的覆盖是3,所以1到2 ( min(3,last[4] ) 的mex变成了5,  此时temp +=2。 temp=5。

    继续,加入5,last[5]=6,4的覆盖是2,所以1到2 ( min(2,last[5] ) 的mex变成了6, 此时temp +=2。 temp=7。

    继续,加入6,last[6]=1,5的覆盖是1,所以1到1 ( min(2,last[5] ) 的mex变成了7, 此时temp +=1。 temp=8。

    到此就结束了。

    所以f[i] = f[i-1] +temp = 9 + 8 =17 。

    下面代码里的mp就是上面分析中说到的覆盖。

     1 #include <bits/stdc++.h>
     2 #define ll long long
     3 using namespace std;
     4 int a[200002],last[200002],mp[200002];  
     5 int main()
     6 {
     7     int n,cnt;
     8     while(scanf("%d",&n)&&n){
     9             for(int i=1;i<=n;i++)
    10                   scanf("%d",&a[i]);
    11             
    12             ll ans=0;
    13             ll temp=0,pre;
    14             memset(last,0,sizeof(last));
    15             memset(mp,0,sizeof(mp));
    16             for(int i=1;i<=n;i++){
    17                   if(a[i]<=n){   //如果大于n,不会影响任何元素,mex的和不变
    18                         pre=last[a[i]];
    19                         last[a[i]]=i;
    20                         for(int j=a[i];j<=n;j++){
    21                               if(j) mp[j]=min(mp[j-1],last[j]);
    22                               else mp[j]=last[j];
    23                               if(mp[j]>pre){
    24                                     temp+=mp[j]-pre;
    25                               }else break;
    26                         }
    27                   }
    28                   ans+=temp;
    29             }
    30             printf("%I64d
    ",ans);
    31     }
    32     return 0;
    33 }
    View Code

    The King’s Ups and Downs

     HDU - 4489 

    题意:给n个人(身高为1到n)排队,问高矮相间的排队方式有几种。

    题解:链接

     1 #include <bits/stdc++.h>
     2 using namespace std;
     3 #define ll long long
     4 const int maxn=22;
     5 ll c[maxn][maxn];
     6 ll dp[maxn][maxn];
     7 ll ans[maxn];
     8 int n;
     9  void init(){
    10      c[1][0]=c[1][1]=1;
    11      for(int i=2;i<maxn;i++){
    12         c[i][0]=1;
    13         for(int j=1;j<=i;j++)
    14             c[i][j]=c[i-1][j-1]+c[i-1][j];
    15      }
    16  }
    17 int main(){
    18     init();
    19     dp[0][0]=dp[0][1]=1;
    20     dp[1][0]=dp[1][1]=1;
    21     ans[1]=1;
    22     for(int i=2;i<=20;i++){
    23         ans[i]=0;
    24         for(int j=1;j<=i;j++){
    25             ans[i]+=(dp[j-1][0]*dp[i-j][1]*c[i-1][j-1]);
    26         }
    27         dp[i][0]=dp[i][1]=ans[i]>>1;
    28     }
    29     int t;
    30     scanf("%d",&t);
    31     while(t--){
    32         int i,k;
    33         scanf("%d%d",&i,&k);
    34         printf("%d %lld
    ",i,ans[k]);
    35     }
    36 }
    View Code

    Number String

     HDU - 4055

    题意:让你求满足字符串s的n排列有多少种。要求,如果s[i]为D,那么第i位小于第i-1位,如果s[i]为I,那么第i位大于第i-1位,s[i]为?时无所谓。

    用dp[i][j]表示第i为排小于等于j的方案数。

     1 #include <bits/stdc++.h>
     2 using namespace std;
     3 const int mod=1000000007;
     4 const int maxn=1010;
     5 char s[maxn];
     6 int dp[maxn][maxn];
     7 
     8 int main(){
     9     while(scanf("%s",s+2)!=EOF){
    10         memset(dp,0,sizeof(dp));
    11         int n=strlen(s+2)+1;
    12         dp[1][1]=1;
    13         for(int i=2;i<=n;i++){
    14             for(int j=1;j<=i;j++){
    15                 dp[i][j]=dp[i][j-1];
    16                 if(s[i]=='D'||s[i]=='?') dp[i][j]=(dp[i][j]+dp[i-1][j-1])%mod;
    17                 if(s[i]=='I'||s[i]=='?') dp[i][j]=((dp[i][j]+(dp[i-1][i-1]-dp[i-1][j-1]))%mod+mod)%mod;
    18             }
    19         }
    20         printf("%d
    ",dp[n][n]);
    21     }
    22     return 0;
    23 }
    View Code

    Water Treatment Plants

     POJ - 1205 

  • 相关阅读:
    基于Canvas的时钟
    注意A链接的默认行为
    基于Aptana3+Django开发blog的示例
    使用vbscript替换excel文件的内容
    使用Ajax建立的Server Push和Iframe建立的Comet
    ajax和它的超时
    通用SQL分页程序
    简简单单学习ASP.NET之三
    功能很强大的UI封装类
    封装的一些实现图片水印与图片自动结合缩放的类
  • 原文地址:https://www.cnblogs.com/yijiull/p/7307955.html
Copyright © 2011-2022 走看看