HDU 2089 不要62 数位dp

问给定区间内,不出现62和4的个数有多少。

第一道数位dp,觉得挺好懂的。

#include <iostream>
#include <functional>
#include <algorithm>
#include <complex>
#include <cstdlib>
#include <cstring>
#include <fstream>
#include <iomanip>
#include <sstream>
#include <utility>
#include <bitset>
#include <cctype>
#include <cstdio>
#include <limits>
#include <memory>
#include <string>
#include <vector>
#include <cmath>
#include <ctime>
#include <queue>
#include <stack>
#include <list>
#include <map>
#include <set>
using namespace std;
const double eps=1e-9;
int n,m,INF=1e9;
int a[10][10];
const int maxn=1e5;
void init()
{
    memset(a,0,sizeof(a));
    a[1][0]=1;
    a[1][1]=1;
    a[1][2]=1;
    a[1][3]=1;
    a[1][4]=0;
    a[1][5]=1;
    a[1][6]=1;
    a[1][7]=1;
    a[1][8]=1;
    a[1][9]=1;
    for (int i=2;i<=8;i++)
    {
        for (int j=0;j<10;j++)
        {
            for (int k=0;k<10;k++)
            {
                if (j!=4&&!(j==6&&k==2))
                a[i][j]=a[i][j]+a[i-1][k];
            }
        }
    }
}
int data[10];
int fun(int num)
{
    int len=1;
    memset(data,0,sizeof(data));
    while (num)
    {
        data[len++]=num%10;
        num/=10;
    }
    int ans=0;
    for (int i=len-1;i>=1;i--)
    {
        for (int j=0;j<data[i];j++)
        {
            if (!(j==2&&data[i+1]==6))
            ans+=a[i][j];
        }
        if (data[i]==4||(data[i+1]==6&&data[i]==2)) break;
    }
    return ans;
}
int main()
{
    init();
    while (scanf("%d%d",&n,&m)&&n&&m)
    {
        printf ("%d\n",fun(m+1)-fun(n));
    }
    return 0;
}

还有一道。给你一个序列,任意打乱顺序,一样的序列算一次,问在全部排列中排名第几。

数位dp计数,预处理是排列组合,方便选位置。

#include <cstdio>
#include <cstring>
#include <cmath>
#include <vector>
#include <algorithm>
using namespace std;
const int INF = 0x3f3f3f3f;
const int N = 2e3+5;
const int mod = 4096;
char s[35];
int a[26],c[35][35];//i位数,某一种有j个,的全部情况。即组合数选位置
int n,ret;
int main()
{
    c[0][0]=1;
    for(int i=1; i<=30; ++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];
//             printf("c[%d][%d]=%d\n",i,j,c[i][j]);
        }
    }
    scanf("%s",s+1);
    n=strlen(s+1);
    for(int i=1; i<=n; ++i)++a[s[i]-'a'];
    for(int i=1; i<=n; ++i)
    {
        for(int j=0; j<s[i]-'a'; ++j)
        {
            if(!a[j])continue;//这一个字母没个数了
            --a[j];//去除这个

            int tmp=1;//答案
            int pp=n-i;//后面还有多少位,剩余的随便填
            for(int j=0; j<26; ++j)
            {
                tmp*=c[pp][a[j]];//直接选位置
                pp-=a[j];
            }
            ret+=tmp;

            ++a[j];//恢复这个
        }
        --a[s[i]-'a'];//这个数字必须放到这位
    }
    printf("%d\n",ret+1);
    return 0;
}

 



posted on 2016-05-13 14:45  very_czy  阅读(106)  评论(0编辑  收藏  举报

导航