FZU 2179 chriswho(数位DP)

题意中文。

因为1-9的lcm是2520,所以对于每一个数模2520,余数如果是自己的lcm的倍数那么就是。

所以dp[i][j][k]代表位数为i,模2520为j,lcm为k的数个数。

枚举后面加的数字g,用dp[i][j][k]去更新dp[i+1][(j*10+g)%2520][lcm(g,k)]。

还要注意一点lcm的个数只有48个,所以就可以开一个数组映射。

写了2种写法,递推写法因为有大量状态浪费速度相当慢。

DFS则快很多

AC代码1:

//#pragma comment(linker, "/STACK:102400000,102400000")
#include<cstdio>
#include<ctype.h>
#include<algorithm>
#include<iostream>
#include<cstring>
#include<vector>
#include<cstdlib>
#include<stack>
#include<cmath>
#include<queue>
#include<set>
#include<map>
#include<ctime>
#include<string.h>
#include<string>
#include<sstream>
#include<bitset>
using namespace std;
#define ll long long
#define ull unsigned long long
#define eps 1e-11
#define NMAX 1000000005
#define MOD 1000000007
#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1
#define PI acos(-1)
template<class T>
inline void scan_d(T &ret)
{
    char c;
    int flag = 0;
    ret=0;
    while(((c=getchar())<'0'||c>'9')&&c!='-');
    if(c == '-')
    {
        flag = 1;
        c = getchar();
    }
    while(c>='0'&&c<='9') ret=ret*10+(c-'0'),c=getchar();
    if(flag) ret = -ret;
}
ll dp[19][2525][50];
int lcm[11][2525],biao[50],m[2525];
map<int,int>mp;
int gcd(int a,int b)
{
    return (b == 0)?a:gcd(b,a%b);
}

void init()
{
    for(int i = 0; i <= 9; i++)
        for(int j = 1; j <= 2520; j++)
            lcm[i][j] = i?i*j/gcd(i,j):j;
    int nct = 1;
    for(int i = 1; i <= 2520; i++) if(2520%i == 0)
    {
        m[i] = nct;
        biao[nct++] = i;
    }
    biao[0] = 1;
//    cout<<biao[48]<<endl;
}

char ch[25];
int main()
{
#ifdef GLQ
    freopen("input.txt","r",stdin);
//    freopen("o4.txt","w",stdout);
#endif // GLQ
    init();
    int cas;
    scanf("%d",&cas);
    while(cas--)
    {
        scanf("%s",ch);
        int len = strlen(ch);
        memset(dp,0,sizeof(dp));
        for(int i = 0; i < ch[0]-'0'; i++)
            dp[0][i][biao[i]] = 1;
        int ha[2];
        ha[0] = ha[1] = ch[0]-'0';
        for(int i = 1; i < len; i++)
        {
            int p = (i==len-1)?ch[i]-'0'+1:ch[i]-'0';
            for(int j = 0; j < p; j++)
                dp[i][(ha[0]*10+j)%2520][m[lcm[j][ha[1]]]] = 1;
            ha[0] = (ha[0]*10+p)%2520;
            ha[1] = lcm[p][ha[1]];
            int num = ch[i]-'0';
            for(int j = 0; j < 2520; j++)
                for(int k = 1; k <= 48; k++) if(dp[i-1][j][k])
                {
                    ll d = dp[i-1][j][k];
                    for(int l = 0; l <= 9; l++)
                    {
                        int lc = m[lcm[l][biao[k]]];
//                        cout<<l<<" "<<lc<<" "<<lcm[l][biao[k]]<<endl;
                        dp[i][(j*10+l)%2520][lc] += d;
                    }
                }
        }
        ll ans = 0;
        for(int i = 0; i < 2520; i++)
            for(int j = 1; j <= 48; j++)
            {
                if(i%biao[j] == 0) ans += dp[len-1][i][j];
            }
        if(len == 1) ans++;
        ans--;
        printf("%I64d\n",ans);
    }
    return 0;
}
AC代码2:

//#pragma comment(linker, "/STACK:102400000,102400000")
#include<cstdio>
#include<ctype.h>
#include<algorithm>
#include<iostream>
#include<cstring>
#include<vector>
#include<cstdlib>
#include<stack>
#include<cmath>
#include<queue>
#include<set>
#include<map>
#include<ctime>
#include<string.h>
#include<string>
#include<sstream>
#include<bitset>
using namespace std;
#define ll long long
#define ull unsigned long long
#define eps 1e-11
#define NMAX 1000005
#define MOD 1000000007
#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1
#define PI acos(-1)
template<class T>
inline void scan_d(T &ret)
{
    char c;
    int flag = 0;
    ret=0;
    while(((c=getchar())<'0'||c>'9')&&c!='-');
    if(c == '-')
    {
        flag = 1;
        c = getchar();
    }
    while(c>='0'&&c<='9') ret=ret*10+(c-'0'),c=getchar();
    if(flag) ret = -ret;
}
ll dp[20][2525][50];
int mp[2520],ha[50],lcm[11][2520],shu[20];

int gcd(int x, int y)
{
    return y?gcd(y,x%y):x;
}

void init()
{
    memset(dp,-1,sizeof(dp));
    int nct = 1;
    for(int i = 1; i <= 2520; i++) if(2520%i == 0)
    {
        ha[nct] = i;
        mp[i] = nct++;
    }
    for(int i = 0;i <= 9; i++)
        for(int j = 1; j <= 2520; j++)
            lcm[i][j] = (i==0)?j:i*j/gcd(i,j);
}

ll dfs(int yu, int lc, int len,int limit)
{
    if(len == 0)
        return yu%ha[lc] == 0;
    if(~dp[len][yu][lc] && !limit) return dp[len][yu][lc];
    ll ans = 0;
    int p = limit?shu[len]:9;
    for(int i = p; i >= 0; i--)
    {
        ans += dfs((yu*10+i)%2520, mp[lcm[i][ha[lc]]],len-1, limit && i == shu[len]);
    }
    if(!limit) dp[len][yu][lc] = ans;
    return ans;
}

int main()
{
#ifdef GLQ
    freopen("input.txt","r",stdin);
//    freopen("o4.txt","w",stdout);
#endif // GLQ
    int cas;
    ll n;
    init();
    scanf("%d",&cas);
    while(cas--)
    {
        scanf("%I64d",&n);
        int nct=1;
        while(n)
        {
            shu[nct++] = n%10LL;
            n /= 10LL;
        }
//        cout<<nct<<endl;
        printf("%I64d\n",dfs(0,1,nct-1,1)-1);
    }
    return 0;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值