Codeforces Round #235 (Div. 2) D. Roman and Numbers 状压dp+数位dp

题目链接:

http://codeforces.com/problemset/problem/401/D

D. Roman and Numbers

time limit per test4 seconds
memory limit per test512 megabytes
#### 问题描述 > Roman is a young mathematician, very famous in Uzhland. Unfortunately, Sereja doesn't think so. To make Sereja change his mind, Roman is ready to solve any mathematical problem. After some thought, Sereja asked Roma to find, how many numbers are close to number n, modulo m. > > Number x is considered close to number n modulo m, if: > > it can be obtained by rearranging the digits of number n, > it doesn't have any leading zeroes, > the remainder after dividing number x by m equals 0. > Roman is a good mathematician, but the number of such numbers is too huge for him. So he asks you to help him. #### 输入 > The first line contains two integers: n (1 ≤ n < 1018) and m (1 ≤ m ≤ 100). #### 输出 > In a single line print a single integer — the number of numbers close to number n modulo m. ####样例输入 > 104 2

样例输出

3

题意

给你n和m,你可以对n的数位进行重排得到新的数,统计所有得到的数中能被m整除的有多少个。

题解

重排所有情况为len!个,len<=18我们可以考虑状压来做,然后处理下%m的余数就可以了。
dp[i][j]表示状态为i,%m==j的所有情况。
最后注意下前导零和去重就可以了。

代码

#include<map>
#include<set>
#include<cmath>
#include<queue>
#include<stack>
#include<ctime>
#include<vector>
#include<cstdio>
#include<string>
#include<bitset>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<functional>
using namespace std;
#define X first
#define Y second
#define mkp make_pair
#define lson (o<<1)
#define rson ((o<<1)|1)
#define mid (l+(r-l)/2)
#define sz() size()
#define pb(v) push_back(v)
#define all(o) (o).begin(),(o).end()
#define clr(a,v) memset(a,v,sizeof(a))
#define bug(a) cout<<#a<<" = "<<a<<endl
#define rep(i,a,b) for(int i=a;i<(b);i++)
#define scf scanf
#define prf printf

typedef __int64 LL;
typedef vector<int> VI;
typedef pair<int,int> PII;
typedef vector<pair<int,int> > VPII;

const int INF=0x3f3f3f3f;
const LL INFL=0x3f3f3f3f3f3f3f3fLL;
const double eps=1e-8;
const double PI = acos(-1.0);

//start----------------------------------------------------------------------

LL dp[1<<19][101];

int main() {
    LL x; int m;
    scf("%I64d%d",&x,&m);

    int arr[22],n=0;
    while(x){ arr[n++]=x%10; x/=10; }

    clr(dp,0);
    dp[0][0]=1;
    bool vis[11];
    rep(i,1,(1<<n)){
        clr(vis,0);
        rep(j,0,n) if(i&(1<<j)){
            ///去除前导零
            if(arr[j]==0&&((i^(1<<j))==0)) continue;
            ///vis用来去重的,相同的数字谁排最后都一样,算一次就够了。
            if(vis[arr[j]]) continue;
            vis[arr[j]]=1;
            rep(k,0,m){
                dp[i][(k*10+arr[j])%m]+=dp[i^(1<<j)][k];
            }
        }
    }

    prf("%I64d\n",dp[(1<<n)-1][0]);

    return 0;
}

//end-----------------------------------------------------------------------

Notes

codeforces的空间限制是512MB!!!,int能开到10^8,long long 能开到5e7。

posted @ 2016-09-20 15:40  fenicnn  阅读(275)  评论(0编辑  收藏  举报