Codeforces Round #235 (Div. 2) D. Roman and Numbers 状压dp+数位dp
题目链接:
http://codeforces.com/problemset/problem/401/D
D. Roman and Numbers
memory limit per test512 megabytes
样例输出
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。