zoukankan      html  css  js  c++  java
  • 运lucky

     

    【问题背景】

      zhx 和妹子们玩数数游戏。


    【问题描述】
      仅包含 4 或7 的数被称为幸运数。
      一个序列的子序列被定义为从序列中删去若干个数, 剩下的数组成的新序列。
      两个子序列被定义为不同的当且仅当其中的元素在原始序列中的下标的集合不
      相等。 对于一个长度为N的序列, 共有2^N个不同的子序列。包含一个空序列) 。
      一个子序列被称为不幸运的,当且仅当其中不包含两个相同的幸运数。
      对于一个给定序列, 求其中长度恰好为 K 的不幸运子序列的个数, 答案mod
      10^9+7输出。


    【输入格式】
      第一行两个正整数N,K,表示原始序列的长度和题目中的 K。
      接下来一行N个整数ai,表示序列中第i 个元素的值。

    【输出格式】
      仅一个数,表示不幸运子序列的个数。(mod


    【样例输入】
      3 2
      1 1 1


    【样例输出】

      3


    【样例输入】
      4 2
      4 7 4 7


    【样例输出】
      4

    【样例解释】
    对于样例 1,每个长度为 2的子序列都是符合条件的。
    对于样例2, 4个不幸运子序列元素下标分别为: {1, 2}, {3, 4}, {1, 4}, {2, 3}。
    注意下标集{1, 3}对应的子序列不是“不幸运”的,因为它包含两个相同的幸运数
    4.


    【数据规模与约定】
    对于50%的数据,1 ≤ N≤ 16。
    对于70%的数据,1 ≤ N≤ 1000, ai ≤ 10000。
    对于100%的数据,1 ≤ N≤ 100000,K ≤ N, 1 ≤ ai ≤ 109。

    这道题前70%的数据显然可以搜索

    但是我一开始认为“仅包含4或仅包含7的数为幸运数”,然而竟过了50分

     1 #include<iostream>
     2 #include<cstring>
     3 #include<cstdio>
     4 using namespace std;
     5 #define int long long
     6 #define MOD 1000000007
     7 #define N 1000100
     8 int n,k,a[N];
     9 int ans,path[N];
    10 int ok[N][3],vis[11][2];
    11 inline int read(){
    12     int x=0; char c=getchar();
    13     while(c<'0'||c>'9') c=getchar();
    14     while('0'<=c&&c<='9') { x=(x<<3)+(x<<1)+c-'0'; c=getchar(); }
    15     return x;
    16 }
    17 inline void check(){
    18     memset(vis,0,sizeof(vis));
    19     for(int i=1;i<=k;i++){
    20         int j=path[i];
    21         if(!ok[j][0]) continue;
    22         if(vis[ok[j][2]][ok[j][1]]) return;
    23         vis[ok[j][2]][ok[j][1]]=1;
    24     }
    25     ans++;
    26 }
    27 void dfs(int minn,int t){
    28     if(t==k+1){
    29         check();
    30         return;
    31     }
    32     for(int i=minn;i<=n;i++){
    33         path[t]=i;
    34         dfs(i+1,t+1);
    35     }
    36 }
    37 #undef int
    38 int main()
    39 #define int long long
    40 {
    41     scanf("%lld%lld",&n,&k);
    42     if(n<=16){
    43         for(int i=1;i<=n;i++){
    44             a[i]=read();
    45             int k=0,b=a[i];
    46             while(b%10==4){
    47                 b/=10; k++;
    48             }
    49             if(k&&!b) {
    50                 ok[i][0]=1;
    51                 ok[i][1]=0; ok[i][2]=k;
    52             }
    53             k=0,b=a[i];
    54             while(b%10==7){
    55                 b/=10; k++;
    56             }
    57             if(k&&!b){
    58                 ok[i][0]=1;
    59                 ok[i][1]=1; ok[i][2]=k;
    60             }
    61         }
    62         dfs(1,1);
    63         printf("%lld
    ",ans);
    64         return 0;
    65     }
    66     return 0;
    67 }

    我们考虑仅包含4或7的数,我们可以用map

    其实数本身对本题是没有影响的,

    只有每种相同幸运数的个数对答案产生影响

    其实我一开始是想出了正解的一半的

    一开始做题时的思路:枚举k个数中不幸运数的个数i,用组合数求出;

    再求出从幸运数中每种不重地选择k-i个数的方案数,相乘

    然而我并不会求后者,于是直接用C(num,k-i)乘了(num为出现的幸运数的总数)

    然而它可以DP

    f[i][j]表示前i中幸运数选j个数的方案数

    lucky[i]表示第i种幸运数的个数

    f[i][j]=f[i-1][j]+f[i-1][j-1]*lucky[i]

     滚动数组可以降一维空间

     1 #include<iostream>
     2 #include<cstring>
     3 #include<cstdio>
     4 #include<map>
     5 using namespace std;
     6 #define int long long
     7 #define MOD 1000000007
     8 #define N 100010
     9 map<int,int> M; 
    10 int n,k,jc[N];
    11 int lucky[N],f[N],num,sum,ans;
    12 inline int read(){
    13     int x=0; char c=getchar();
    14     while(c<'0'||c>'9') c=getchar();
    15     while('0'<=c&&c<='9') { x=(x<<3)+(x<<1)+c-'0'; c=getchar(); }
    16     return x;
    17 }
    18 inline int qpow(int x,int k){
    19     int s=1;
    20     while(k){
    21         if(k&1) s=s*x%MOD;
    22         k>>=1;
    23         x=x*x%MOD;
    24     }
    25     return s;
    26 }
    27 int C(int m,int n){
    28     if(m<n) return 0;
    29     if(m==n) return 1;
    30     if(n>m-n) n=m-n;
    31     int x=jc[m]*qpow(jc[m-n]*jc[n]%MOD,MOD-2)%MOD;
    32     return x;
    33 }
    34 #undef int
    35 int main()
    36 #define int long long
    37 {
    38     freopen("lucky10.in","r",stdin);
    39     scanf("%lld%lld",&n,&k);
    40     int x;
    41     for(int i=1;i<=n;i++){
    42         x=read();
    43         int k=0,y=x;
    44         while(y%10==4||y%10==7)
    45         { y/=10; k++; }
    46         if(k&&!y){
    47             if(!M[x]){
    48                 lucky[++num]++;
    49                 M[x]=num;
    50             }
    51             else lucky[M[x]]++;
    52             sum++;
    53         }
    54     }
    55     f[0]=1;
    56     for(int i=1;i<=num;i++)
    57      for(int j=min(k,i);j>=1;j--)
    58       f[j]=(f[j]+f[j-1]*lucky[i])%MOD;
    59     jc[0]=1;
    60     for(int i=1;i<=n;i++)
    61      jc[i]=jc[i-1]*i%MOD;
    62     for(int i=0;i<=k;i++)
    63      ans=(ans+C(n-sum,i)*f[k-i]%MOD)%MOD;
    64     printf("%lld
    ",ans);
    65     return 0;
    66 }

     

  • 相关阅读:
    C语言文本文件实现局部修改
    TTMS框架设计思路及实例介绍
    浅谈函数与操作符的重载
    Java:继承与多态
    Java:类与对象(二)
    Java : 类与对象(一)
    C语言 数的阶乘、高次幂、大数加法及大数乘法
    C语言下的位运算
    enum:枚举类型介绍与简单使用
    C语言实现字符界面下的学生管理成绩系统
  • 原文地址:https://www.cnblogs.com/yjkhhh/p/9372377.html
Copyright © 2011-2022 走看看