zoukankan      html  css  js  c++  java
  • 7.9模拟赛

    dp专场既视感

    T1.gift

    有约束的背包。

    先把原序列排序,从小到大,对于其中第x个元素,我们假设它是最小的没有被选的物品,那么小于a[x]的都要被强制选择。

    这就会影响统计答案的区间,变成( m-s[i-1],m-s[i] ]。

    其余正常转移即可。

    #include<algorithm>
    #include<iostream>
    #include<cstdio>
    
    using namespace std;
    
    const int MAXN=1005;
    const int MOD=1e9+7;
    
    
    int f[MAXN];
    int a[MAXN],s[MAXN];
    
    int n,m,ans;
    
    int main(){
        cin>>n>>m;
        f[0]=1;
        for(int i=1;i<=n;i++) cin>>a[i];
        sort(a+1,a+1+n);
        for(int i=1;i<=n;i++) s[i]=s[i-1]+a[i];
        for(int i=n;i>=1;i--){
            for(int j=m-s[i-1];j>=0&&j>m-s[i];j--)(ans+=f[j])%=MOD;
            for(int j=m;j>=a[i];j--)(f[j]+=f[j-a[i]])%=MOD;
        }
        if(s[n]<=m) ans++;
        cout<<ans%MOD;
        return 0;
    }

     T2.fseq

    求概率,想到分母肯定是C(n+m,n),可是分子呢。。

    把+1看成向右走,-1看成向上走,就是在一个N*M的网格图中从原点走到(N,M)的方案数了,这是一个不降路径问题 ,答案为C(n+m,n)

    可是这里说任意前缀和不能小于0,所以我们可以形象化这个约束条件,也就是不穿过对角线,神奇的卡特兰数来了。

    (C(n+m,n)-C(n+m,n-1))/C(n+m,n)

    化简以后就是1-m/(n+1)

    代码实现,注意m>n的情况要特判。

    #include<iostream>
    #include<cstdio>
    
    using namespace std;
    
    int n,m,T;
    int main(){
        cin>>T;
        while(T--){
            cin>>n>>m;
            if(n<m){
                puts("0.000000");
                continue;
            }
            printf("%.6lf
    ",1.0-m*1.0/(n+1.0));
        }
        return 0;
    }

     T3.lucky

    看起来是数位DP,可以用递归的形式做。

    这个问题有明显的子问题性质,对于一个长度为n的数,我们可以分开它的前n-1位和第n位进行考虑,而前n-1位就又是一个子问题了。

    考虑计算一个长度为n的数的第x位,它若是等于对称的n-x+1位,那就直接返回。

    从中间分开这个序列,前半部分是可以随意填写的,而后半部分就要受到约束(反之亦然成立),约束是一一对应的,所以前半部分是10为底的幂,后半部分是9为底的幂。

    预处理形如999...999的数,可以在累计答案时直接加入。

    GSH真是太强啦

    #include<iostream>
    #include<cstdio>
    #define int long long
    using namespace std;
    
    const int MAXLEN=20;
    
    int po(int x,int y){
      int ret=1;
      for(int base=x;y;y>>=1,base*=base) if(y&1) ret*=base;
      return ret;
    }
    
    int a[MAXLEN],res[MAXLEN],bp;
    int len;
    
    int calc(int x){
      int tmp=a[x],ans=0ll;
      if(x==len||(x<bp&&a[x]>a[len-x+1])) tmp--;
      ans+=tmp*po(10,max(0ll,x-bp))*po(9ll,min(x-1,bp-1));
      if(x<bp&&a[x]==a[len-x+1]) return ans;
      if(x==1) return ans+1ll;
      ans+=calc(x-1);
      return ans;
    }
    
    int solve(int x){
      len=0;
      if(x==0) return 0;
      int ans=0;
      while(x){
        a[++len]=x%10;
        x/=10;
      }
      ans+=res[len-1];
      bp=(len/2)+1;
      ans+=calc(len);
      return ans;
    }
    
    void prework(){
      for(int i=1,tmp=9;i<=18;i++,tmp=tmp*10+9) res[i]=solve(tmp);
    }
    
    signed main(){
      int na,nb;
      cin>>na>>nb;
      prework();
      cout<<solve(nb)-solve(na-1);
      return 0;
    }

     

    本文来自博客园,作者:GhostCai,转载请注明原文链接:https://www.cnblogs.com/ghostcai/p/9285781.html

  • 相关阅读:
    .net中使用JQuery Ajax判断用户名是否存在的方法
    简单的SqlHelper
    C#中邮件的发送基本操作
    身份证号码组成 含代码
    C#和asp.net中链接数据库中 参数的几种传递方法
    【转】iptables 命令介绍
    sed的替换命令
    【转】sed 的参数
    【转】sed正则表达式
    【转】shell中如何判断一个变量是否为空
  • 原文地址:https://www.cnblogs.com/ghostcai/p/9285781.html
Copyright © 2011-2022 走看看