zoukankan      html  css  js  c++  java
  • 洛谷 数字 解题报告

    数字

    题目描述

    一个数字被称为好数字当他满足下列条件:

    1. 它有2*n个数位,n是正整数(允许有前导0)。

    2. 构成它的每个数字都在给定的数字集合S中。

    3. 它前n位之和与后n位之和相等或者它奇数位之和与偶数位之和相等
      例如对于n=2,S={1,2},合法的好数字有 1111、1122,1212,1221,2112,2121,2211,2222这样8种。

    已知n,求合法的好数字的个数mod 999983。

    输入输出格式

    输入格式:

    第一行一个数n。

    接下来一个长度不超过10的字符串,表示给定的数字集合。

    输出格式:

    一行一个数字表示合法的好数字的个数mod 999983。

    说明

    对于20%的数据,n≤7。

    对于100%的.据,n≤1000,|S|≤10。


    首先,用DP分别求出满足“前n位之和与后n位之和相等”和“奇数位之和与偶数位之和相等”的,再用容斥原理把它们的交集减去。

    第一步很好求,我们发现每个数的位置并不重要,重要的是它的规模(n)

    (dp[i][j])代表规模为(i)的数的和为(j)的时候一共有多少种方案数构成

    则第一步的答案为((sum_{i=0}^{mx*n} dp[n][i]^2)*2)(mx)为给定数字集合中最大的数

    当两个条件同时满足时,可以如下的充分描述:
    前一块中的奇数和等于后一块的偶数和,前一块的偶数和等于后一块的奇数和

    为什么要这么描述?因为我们要保证划分出来的子集是不相交的,如果划分出来的子集有包含关系,岂不是求不了嘛

    因为(n)可能是奇数,所以令(k_1)为奇数块规模,(k_2)为偶数块规模,我们发现这和之前的问题是一样的

    则对“前一块中的奇数和等于后一块的偶数和”这一步的答案为(sum_{i=0}^{mx*max(k1,k2)} dp[k1][i]*dp[k2][i])

    对“前一块的偶数和等于后一块的奇数和”的答案同样是上一行。

    把两个答案乘起来即为之前两块的交集


    code:

    #include <cstdio>
    #include <cstring>
    #define ll long long
    ll max(ll x,ll y){return x>y?x:y;}
    const int N=1001;
    const int mod=999983;
    ll dp[N][N*10],a[12],mx,ans;
    int n,len;
    char c[12];
    void DP()
    {
        dp[0][0]=1;
        for(int i=1;i<=n;i++)
        {
            int r=mx*i;
            for(int j=0;j<=r;j++)
                for(int k=1;k<=len;k++)
                    if(j>=a[k])
                        dp[i][j]=(dp[i][j]+dp[i-1][j-a[k]])%mod;
        }
    }
    void cal()
    {
        for(int i=0;i<=mx*n;i++)
            ans=(ans+dp[n][i]*dp[n][i]%mod)%mod;
        ans<<=1;
        int k1=n>>1,k2=n+1>>1;
        ll a0=0,a1=0;
        for(int i=0;i<=k1*mx;i++)
            a0=(a0+dp[k1][i]*dp[k1][i]%mod)%mod;
        for(int i=0;i<=k2*mx;i++)
            a1=(a1+dp[k2][i]*dp[k2][i]%mod)%mod;
        ans=(ans+mod-a0*a1%mod)%mod;
    }
    int main()
    {
        scanf("%d",&n);
        scanf("%s",c);
        len=strlen(c);
        for(int i=1;i<=len;i++)
        {
            a[i+1]=c[i]-'0';
            mx=max(mx,a[i+1]);
        }
        DP();
        cal();
        printf("%lld
    ",ans);
        return 0;
    }
    
    

    2018.6.26

  • 相关阅读:
    端口扫描器的几种代码实现方案
    滴滴推理引擎IFX:千万规模设备下AI部署实践
    报名啦!第四届滴滴-IEEE未来精英论坛今夏来袭
    torch单机多卡重点:
    常见异常总结,入职阿里巴巴大概率面试题!!!
    龙小树 | R语言学习参考用书推荐
    英文写作常用网址
    LaTeX常用链接与资料
    LaTeX:算法模板
    崩溃中!我终于看明白了,什么是财富自由的底层逻辑!思维导图+笔记精华
  • 原文地址:https://www.cnblogs.com/butterflydew/p/9230756.html
Copyright © 2011-2022 走看看