zoukankan      html  css  js  c++  java
  • 【好好补题,因为没准题目还会再出第三遍!!】ACM字符串-组合数学(官方题解是数位DP来写)

    ACM字符串
    1.长度不能超过n
    2.字符串中仅包含大写字母
    3.生成的字符串必须包含字符串“ACM”,ACM字符串要求连在一块!
    
    ok,是不是很简单?现在告诉你n的值,你来告诉我这样的字符串有多少个
    
    输入
    
    输入一个正整数T,代表有T组数据 
    接下来T行,每行一个正整数n,n<=10。 
    
    输出
    
    输出符合条件的字符串的数目
    
    样例输入
    
    1
    3
    
    
    样例输出
    
    1

    做题过程:

    1. 熬了三四个小时,WA了无数次!最终推出了组合数的公式!
    2. 首先暴力打表,嘿嘿!这样极大地压缩计算时间!
    3. 打表如下:

      一:生成连续的7位绝对不含ACM的数据的个数!

      ll Els[10];//生成7位绝对不含ACM的数据
      int a[10];
      
      void dfs(int now,int len)
      {
          if(now>len)
          {
              Els[len]++;
              return ;
          }
          for( int i=1; i<=26; i++)
          {
              a[now]=i;
              if(now>=3&&a[now]==3&&a[now-1]==2&&a[now-2]==1)
                  continue;
              dfs(now+1,len);
          }
      }
      int main()
      {
      
          for(int i=1; i<=3; i++)
          {
              dfs(1,i);
              printf("i=%d, %lld
      ",i,Els[i]);
          }
      
          cout<<"生成连续的7位绝对不含ACM的数据"<<endl;
          for(int i=1; i<=3; i++)
          {
              printf("i=%d, %lld
      ",i,Els[i]);
          }
      
          return 0;
      }
    4. 二:开始进行组合数学处理,并且处理误差!

    5. 误差是怎么回事呢?举个栗子当“n=6时,形如当只含有一个ACM时—— “ACM_ _ _”这种样子C(4,1)种组合数(把ACM捆绑成一块!),然后需要C(4,1) 乘于其余三个空位上的数字组合,这三种数字“因为不能再含有ACM”直接调用上面求出的Els[3], 但是这里存在了误差!
    6. 仔细考虑一下,当出现“_ACM_ _”的组合的这种情况时,其实有Els[1]*Els[2] 种!也就是说中间的“ACM”隔开了两边,我上面求的那么“Els”的真实意思是“生成连续的7位绝对不含ACM的数据个数”!Els[1]*Els[2] -Els[3] = 1 ,这里的误差就是1!以此类推!
    7. 同理,其他的情况也是如此!多的位数可以跑循环进行枚举!手写就有点麻烦了!
    #define ll long long
    ll F[12]; //n的阶乘
    //ll f[12];
                    ///chart表示连续的绝对不含ACM连续的字符串个数,就是上面求出的"Els 数组"
    ll chart[12]={1,  26,676,17575,  456924,11879348,308845473,  8029525374};
    ll mistake[12];    ///存储每个长度n的误差!
    ll Cul(int m,int k)  //计算C(m,k)的组合数
    {
        return F[m]/(F[k]*F[m-k] );
    }
    ll ans[12]={0,0,0,1};
    void init(){
        F[0]=1;
        for(int i=1;i<=10;i++)  //n的阶乘!
            F[i]=F[i-1]*i;
        memset(mistake,0,sizeof(mistake));
        mistake[6]+= chart[1]*chart[2]*2- 2*chart[3];
        mistake[7]+= chart[1]*chart[3]*2+chart[2]*chart[2]- 3*chart[4];
        mistake[8]+= chart[1]*chart[4]*2+chart[2]*chart[3]*2- 4*chart[5];
        mistake[9]+= chart[1]*chart[5]*2+chart[2]*chart[4]*2+chart[3]*chart[3] - 5*chart[6];
        mistake[9]+= chart[1]*chart[2]*6 +chart[1]*chart[1]*chart[1] - chart[3]*7;
    
        for(int i=1;i<=7;i++)  ///__A_____
            mistake[10]+=chart[i]*chart[7-i]-chart[7];
        for(int j=0;j<=4;j++){
            for(int i=0;i+j<=4;i++)  ///_A__A__(空出j个位置和i个位置和4-i-j个位置!!)
                mistake[10]+=chart[j]*chart[i]*chart[4-i-j]-chart[4];
        }
    
    
    }
    int main(){
    
        init();
    
        for(int j=4;j<=10;j++)
        {
           int n=j;
            int num=n/3;
             ans[j]=ans[j-1];
            for(int i=1;i<=num;i++){  //单个的,结果需要累加!!
                ans[j]+=Cul(i+n-i*3,i)*chart[n-i*3] ;
            }
          //   printf("j=%d, %lld
    ",j,ans[j]);
            ans[j]+= mistake[j];
         //   printf("+mis::  j=%d, %lld
    ",j,ans[j]);
        }
    
        int T;
        scanf("%d",&T);
    
        while(T--){
            int n;
            cin>>n;
    
            printf("%lld
    ",ans[n]);
        }
    
        return 0;
    }

    官方题解是数位DP来写,数位DP其实就是记忆化搜索+深搜!建议学学!

  • 相关阅读:
    Codeforces Round #619 (Div. 2) ABC 题解
    Codeforces Round #669 ABC 题解
    中大ACM个人赛 ABC题题解
    Codeforces Round #601 (Div. 2) ABC 题解
    SCAU 2019年校赛 部分题解
    SCAU 2018年新生赛 初出茅庐 全题解
    Educational Codeforces Round 74 (Rated for Div. 2) ABC 题解
    Codeforces Round #603 (Div. 2) ABC 题解
    【题解】 CF767E Change-free 带悔贪心
    【题解】 NOIp2013 华容道 最短路+状态压缩 Luogu1979
  • 原文地址:https://www.cnblogs.com/zhazhaacmer/p/9690913.html
Copyright © 2011-2022 走看看