• 数位dp专题



    这个题的数据特别大,很容易想到数位dp,但是判断条件是啥不清楚
    打表发现这个函数f(n)就是二进制下的翻转每个位
    要想f(n)=n,n必须为回文数

    很明显的数位dp 发现正向推判断的时候会超时 再看见至少这两个字 引导你去往容斥的方向去想

    至少重复出现一次的反面就是均不重复出现 这样我们dfs的时候用个2048的数来状压记录一下就好了

    #include<bits/stdc++.h>
    using namespace std;
    #define lowbit(x) x&(-x)
    #define ll long long
    const int maxn=40;
    const int maxx=2050;
    int n,cnt;
    void calc(int);
    int a[maxn];
    ll dp[maxn][maxx][2][2]; 
    ll dfs(int pos,int mp,int limit,int lead){
    	if(pos==cnt+1)return 1;
    	if(dp[pos][mp][limit][lead]!=-1)return dp[pos][mp][limit][lead];
    	ll ans=0;
    	int up=limit?a[pos]:9;
    	for(int i=0;i<=up;i++){
    		if(lead&&i==0)ans+=dfs(pos+1,0,limit&&i==a[pos],1);
    		else if(!((mp>>(i+1))&1))
    		ans+=dfs(pos+1,mp|(1<<(i+1)),limit&&i==a[pos],0);
    	}
    	return dp[pos][mp][limit][lead]=ans;
    }
    int main(){
    	cin>>n;
    	calc(n);
         return 0;
    }
    void calc(int x){
    	while(x){
    		a[++cnt]=x%10;
    		x/=10;
    	}
    	reverse(a+1,a+1+cnt);
    	memset(dp,-1,sizeof(dp));
    	cout<<n-dfs(1,0,1,1)+1;
    }
    

    这个题和上面一题类似 可以状压 但是唯一不同的就是这个题要求和

    怎么办? 维护两个dp数组 dp1表示方案数 dp2表示答案

    对于每一个位置pos 枚举到的i 对答案产生的贡献为 dp2+=dp1 乘 10的pos次方乘i

    #include <bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    const int N = 3e6 + 10;
    const int mod = 998244353;
    typedef pair<ll, ll> pii;
    ll dp[10005][2048];
    ll dp2[10005][2048];
    int a[10005], st;
    ll base[10005];
    pii dfs(int pos, int state, bool limit, bool lead) {
        if (pos == -1) {
            if ((state & st) == st) return {1,0};
            else return {0,0};
        }
        if (!limit && !lead && dp[pos][state] != -1) return {dp[pos][state], dp2[pos][state]};
        int End = limit ? a[pos] : 9;
        ll ans1 = 0, ans2 = 0;
        for (int i = 0; i <= End; i++) {
            if (lead&&i==0) {
                    pii tmp = dfs(pos-1, state, limit && i == End, 1);
                    ans1 = (ans1 + tmp.first) % mod;
                    ans2 = (ans2 + i * base[pos] % mod * tmp.first % mod + tmp.second) % mod;
                }
                else {
                    pii tmp = dfs(pos-1, state | (1<<i), limit && i == End, 0);
                    ans1 = (ans1 + tmp.first) % mod;
                    ans2 = (ans2 + i * base[pos] % mod * tmp.first % mod + tmp.second) % mod;
                }
        }
        if (!limit && !lead) dp[pos][state] = ans1, dp2[pos][state] = ans2;
        return {ans1, ans2};
    }
    int main() {
        base[0] = 1;
        for (int i = 1; i <= 10000; i++) base[i] = base[i-1] * 10 % mod;
        string s; cin >> s;
        int len = s.size();
        int m; cin >> m;
        for (int i = 1; i <= m; i++) {
            int x; cin >> x;
            st |= 1 << x;
        }
    
        for (int i = 0; i < s.size(); i++) a[i] = s[len-1-i]-'0';
        memset(dp, -1, sizeof dp);
        memset(dp2, -1, sizeof dp2);
        cout << dfs(len-1, 0, true, true).second << endl;
    }
    
    
    
  • 相关阅读:
    JAVA_Collection容器
    ArrayList实现分组功能
    scrapy 安装出错 [err2] no such file or directory: 'README.rst'【已解决】
    python spyder 今天突然打不开了【已解决】
    SVN使用教程总结
    MVC框架浅析(基于PHP)
    Web性能优化方案
    野生程序员的故事
    js控制页面跳转,清缓存,强制刷新页面
    js中json处理总结之JSON.parse
  • 原文地址:https://www.cnblogs.com/wzxbeliever/p/15823500.html
Copyright © 2020-2023  润新知