• 数位DP


     

    CodeForces 55D : Beautiful numbers

    题意 : 求 【L,R】之间能被自己每一位非0数整除的数的个数。

    1-9的LCM是比较小的, 但是直接开会爆, 需要离散化, 这题关键 lcm 和 离散了

    #include<bits/stdc++.h>
    using namespace std;
    const int maxn = 2520;
    
    int gcd(int a, int b) {return b ? gcd(b, a%b): a; }
    int lcm(int a, int b) {return a / gcd(a, b) * b;  }
    
    int index[maxn + 50];
    void Get_Index()
    {
        int l = 0;
        for(int i = 1; i <= maxn; ++i)
        {
            if(maxn % i == 0)
                index[i] = l++;
        }
    }
    
    typedef long long LL;
    LL Dp[50][maxn][100];
    int Num[100];
    LL DFS(int L, int sum, int mod, bool e) {
        if(L == -1) return sum % mod == 0;
        if(!e && Dp[L][sum][index[mod]] != -1) return Dp[L][sum][index[mod]];
        int u = e ? Num[L] : 9;
        LL ret = 0;
        for(int i = 0; i <= u; ++i)
            ret += DFS(L-1, (sum*10+i)%maxn, i?lcm(mod, i):mod, e&&(i==u));
        return e ? ret : Dp[L][sum][index[mod]] = ret;
    }
    
    LL Solve(LL N) {
        int L = 0;
        while(N) {
            Num[L++] = N%10;
            N/=10;
        }
        return DFS(L-1,0,1,1);
    }
    
    int main()
    {
        Get_Index();
        int t;
        LL A, B;
        cin >> t;
        memset(Dp, -1, sizeof(Dp));
        while(t--)
        {
            cin >> A >> B;
            LL Ans = A ? (Solve(B)-Solve(A-1)) : Solve(B);
            cout << Ans << endl;
        }
    }
    

     HDU 4352 XHXJ's LIS

    题意 : 求数字的位数数升序刚好为 K 的数的个数。

    直接状态不好开, 平常我们求LIS 的思想, 可以转化, 状态压缩, 用二进制的 1 的个数表是 LIS 的长度

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long LL;
    const int maxn = 1<<11;
    LL Dp[20][maxn][11];
    LL Num[20], A, B, K;
    
    int GetOne(int s) {
        int ret = 0;
        while(s) {
            if(s & 1) ret ++;
            s >>= 1;
        }
        return ret;
    }
    
    int GetState(int n, int s) {
        /// 运用 二分求 LIS 的思想
        for(int i = n; i < 10; ++i)
            if(s&(1<<i)) return (s^(1<<i))|(1<<n);
        return s|(1<<n);
    }
    
    LL DFS(int L, int state, bool isz, bool e) {
        if(L == -1) return GetOne(state) == K;
        if(!e && Dp[L][state][K] != -1) return Dp[L][state][K];
        int u = e ? Num[L] : 9;
        LL ret = 0;
        for(int i = 0; i <= u; ++i)
            ret += DFS(L-1, (isz&&(i==0))?0:GetState(i,state), (isz&&(i==0)), e&&(i==u));
        return e ? ret : Dp[L][state][K] = ret;
    }
    
    LL Solve(LL N) {
        int L = 0;
        while(N) {
            Num[L++] = N % 10;
            N /= 10;
        }
        return DFS(L-1, 0, 1, 1);
    }
    
    int main()
    {
        memset(Dp,-1,sizeof(Dp));
        int t;
        scanf("%d", &t);
        for(int kase = 1; kase <= t; ++kase) {
            scanf("%lld %lld %lld", &A, &B, &K);
            printf("Case #%d: %lld
    ",kase, Solve(B)-Solve(A-1));
        }
    }
    

     HDU 2089 不要62    、 HDU 3555Bomb、      POJ 3252 (转换成二进制数)

    经典熟悉板子的题了

    HDU 3709 Balanced Number 

    题意 : 求出 平衡数的个数, 类似杠杆, 利用 权值和为 0 , 枚举中心就好了

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long LL;
    const int maxn = 20;
    LL Num[20], Dp[20][20][1000][2];
    
    LL DFS(int L, int mid, int sum, bool e) {
        if(L == -1) return sum ? 0 : 1;
        if(!e && Dp[L][mid][sum][e]!= -1) return Dp[L][mid][sum][e];
        LL ret = 0;
        int u = e ? Num[L] : 9;
        for(int i = 0; i <= u; ++i)
        {
            int tmp = (L-mid) * i + sum;
            if(tmp >= 0)
                ret += DFS(L-1, mid, tmp, e && (i==u));
        }
        return e ? ret : Dp[L][mid][sum][e] = ret;
    }
    
    LL Solve(LL N)
    {
        int L = 0;
        while(N) {
            Num[L++] = N % 10;
            N /= 10;
        }
        ///
        LL Ans = 0;
        for(int i = 0; i < L; ++i)
        {
            memset(Dp,-1,sizeof(Dp));
            Ans += DFS(L-1, i, 0, 1)-1;
        }
        return Ans + 1;
    }
    
    int main()
    {
        int t;
        LL A, B;
        cin >> t;
        while(t--)
        {
            cin >>A >> B;
            cout << Solve(B)-Solve(A-1) <<endl;
        }
        return 0;
    }
    

     HDU 4507 

    题目转换成求平方和;

    需要数学公式先推导一下,

    (a+b1)^2 + (a+b2)^2 + ... + (a+bn)^2 = n*a^2 + 2*a*(b1+b2+...+bn) + (b1^2 + b2^2 + ... + bn^2)

    保存 num 个数 , sum 和, sum2 平方和三个状态,就可以快速求出值了。

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long LL;
    const LL MOD = 1e9 + 7;
    struct Node {      
    	LL num, sum, sum2;
    	Node(LL a = 0, LL b = 0, LL c = 0) :
    		num(a), sum(b), sum2(c) {} 
    };
    
    bool Vis[30][10][10];
    Node Dp[30][10][10];
    LL Num[30];
    LL Pow[30];
    
    void INIT() {  
    	memset(Vis, 0, sizeof(Vis));
    	Pow[0] = 1; 
    	for(int i = 1 ; i < 20; ++i) Pow[i] = Pow[i-1]*10;
    }
    
    Node DFS(LL Len, LL Sum, LL Mod, bool e) {
    	if(Len == -1) {
    		if(Sum == 0 || Mod == 0) return Node(0,0,0);
    		else return Node(1,0,0);
    	}
    	if(!e && Vis[Len][Sum][Mod]) return Dp[Len][Sum][Mod];
    	int u = e ? Num[Len] : 9;
    	Node ret, tmp;
    	for(int i = 0; i <= u; ++i)
    	{
    		if(i == 7) continue ;
    		tmp = DFS(Len-1, (Sum+i) % 7, (Mod*10+i) % 7, e && (i==u));
    		LL d = i * (Pow[Len] % MOD) % MOD;
    		ret.num  = (tmp.num + ret.num) % MOD;
    		ret.sum  = (d * tmp.num % MOD + tmp.sum + ret.sum) % MOD;
    		ret.sum2 = (d*d%MOD*tmp.num%MOD + tmp.sum2 + ret.sum2 + 2 * d * tmp.sum % MOD) % MOD;
    	}
    	if(!e) {
    		Vis[Len][Sum][Mod] = true;
    		Dp[Len][Sum][Mod] = ret;
    	}
    	return ret;
    }
    
    LL Solve(LL N) {
    	int L = 0;
    	while(N) {
    		Num[L++] = N % 10;
    		N /= 10;
    	}
    	return DFS(L-1, 0, 0, 1).sum2;
    }
    
    int main()
    {
    	INIT();
    	int t;
    	cin >> t;
    	LL L, R;
    	while(t--)
    	{
    		cin >> L >> R;
    		cout << (Solve(R) - Solve(L-1) + MOD) % MOD << endl;
    	}
    	return 0;
    }
    
  • 相关阅读:
    让程序调用运行linux shell命令
    纯C的字符串问题
    Linux的打包和解压缩命令
    ubuntu安装mosquitto-1.4.5
    无Teamview授权,使用Teamview方式
    有效利用家用宽带,动态域名服务(DDNS)
    pfx格式证书转成nginx可用的证书
    iis文件上传限制
    vue脚手架使用
    netcore中执行linux命令
  • 原文地址:https://www.cnblogs.com/aoxuets/p/5506854.html
Copyright © 2020-2023  润新知