zoukankan      html  css  js  c++  java
  • bzoj1072排列

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=1072

    好像是这方面的裸题。

    整除k 要想转移需要记录下 达到模k所有余数 的方案数。

    为了生成排列,状压记录当前已用了原数组中的哪些位置;

    因为是无顺序地取用的,所以可以有顺序地放在目标数组中,即续在上一个数后面;所以 导致的余数 就是 之前余数*10+这个数。

      另一种想法是有顺序取用、无顺序放置;即用了前 i 个数,状压记录放在了哪些位置上;新加入一个数的贡献是 之前余数+这个数*1ek。

      感觉第一种比较方便?

    循环的顺序需要注意!要把状压的状态 j 放在最外面,而不是当前位置 i 。

    dp的初值需要想想。

    对于值相等的一些数字,在排列中无区别,dp的时候却有区别地对待了。

      只需要对于每一组,答案除去它们的排列数(即阶乘)即可。

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    using namespace std;
    int t,a[15],cnt,k,d[1030][1005],lm,ans,num[15];
    char ch;
    int kj[15]={1,1,2,6,24,120,720,5040,40320,362880,3628800};
    int main()
    {
        scanf("%d",&t);
        while(t--)
        {
            cnt=0;ans=0;
            memset(d,0,sizeof d);
            memset(num,0,sizeof num);
            d[0][0]=1;/////
            scanf(" %c",&ch);
            while(ch>='0'&&ch<='9')
            {
                a[++cnt]=ch-'0';
                num[a[cnt]]++;
                ch=getchar();
            }
            lm=(1<<cnt);
            scanf("%d",&k);
            for(int j=0;j<lm;j++)//当前取用了原串中哪些位置(按顺序后续着放下) 
                for(int i=1;i<=cnt;i++)
                    if((j&(1<<(i-1)))==0)
                        for(int l=0;l<k;l++)
                            d[j|(1<<(i-1))][(l*10+a[i])%k]+=d[j][l];
            ans=d[lm-1][0];
            for(int i=0;i<=9;i++)ans/=kj[num[i]];
            printf("%d
    ",ans);
        }
        return 0;
    }
  • 相关阅读:
    单位
    北京户口
    中科院助理工程师
    SQL学习
    question
    ROI选取过程
    IT学习网站
    撞库 拖库
    善用人类记忆的特点去高效学习
    为什么散步对健康很有益处
  • 原文地址:https://www.cnblogs.com/Narh/p/8673665.html
Copyright © 2011-2022 走看看