首页 > 其他 > 详细

LA 6529 Eleven dp

时间:2015-02-05 23:26:27      阅读:387      评论:0      收藏:0      [点我收藏+]

题意:给一个数字串,可以调换数字,问有多少种组合可以让组成的数能被11整除。

思路:窝们观察到1%11=1, 10%11=10,100%11=1,1000%11=10,以此类推。。窝们将一偶一奇看作一对,这一对组成对11的余数

×100对11的余数(也就是1),所以实质还是这一对对11的余数,那么奇偶数位的和就可以了。我们可以设奇数位的和为x,偶数位的

和为y,则(x+10y)%11的值为0就可以了--> (x-y+11y)%11=0 --> (x-y)%11=0。所以设dp[i][j][k]表示处理完0到i-1,已在奇数位放了j个

数字,(奇数位数字和-偶数位数字和)%11=k的种数,详见代码:

/*********************************************************
  file name: LA6529.cpp
  author : kereo
  create time:  2015年02月04日 星期三 20时39分19秒
*********************************************************/
#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
#include<set>
#include<map>
#include<vector>
#include<stack>
#include<cmath>
#include<string>
#include<algorithm>
using namespace std;
typedef long long ll;
const int sigma_size=26;
const int N=15;
const int MAXN=100+10;
const int inf=0x3fffffff;
const double eps=1e-8;
const int mod=1000000000+7;
#define L(x) (x<<1)
#define R(x) (x<<1|1)
#define PII pair<int, int>
#define mk(x,y) make_pair((x),(y))
char str[MAXN];
int num[N];
ll C[MAXN][MAXN];
ll dp[N][MAXN][N];//dp[i][j][k]表示处理完0到i-1,已在奇数位放了j个数字,(奇数位数字和-偶数位数字和)%11=k的种数
void init(){
    for(int i=0;i<MAXN;i++){
        C[i][0]=C[i][i]=1;
        for(int j=1;j<i;j++)
            C[i][j]=(C[i-1][j-1]+C[i-1][j])%mod;
    }
}
ll solve(int len){
    memset(dp,0,sizeof(dp));
    dp[0][0][0]=1;
    int sum=0,n=(len+1)>>1;
    for(int i=0;i<10;i++){ //处理的数位
        for(int j=0;j<=sum && j<=n;j++){ //已放在奇数位的个数
            for(int k=0;k<=num[i] && k<=n-j;k++){ //这次在奇数位放的个数
                int x=((2*k-num[i])*i)%11;
                if(x<0)
                    x+=11;
                for(int st=0;st<=10;st++){
                    dp[i+1][j+k][(st+x)%11]=((((dp[i][j][st]*C[n-j][k])%mod)*C[len-sum-(n-j)][num[i]-k])%mod+dp[i+1][j+k][(st+x)%11])%mod;
                }
            }
        }
        sum+=num[i];
    }
    return dp[10][n][0];
}
int main(){
    init();
    while(~scanf("%s",str)){
        memset(num,0,sizeof(num));
        int n=strlen(str);
        for(int i=0;i<n;i++)
            num[str[i]-'0']++;
        ll ans1=solve(n),ans2=0;
        if(num[0]){ //剔除前导零的情况
            num[0]--;
            ans2=solve(n-1);
        }
        printf("%lld\n",((ans1-ans2)%mod+mod)%mod);
    }
	return 0;
}


LA 6529 Eleven dp

原文:http://blog.csdn.net/u011645923/article/details/43538107

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!