zoukankan      html  css  js  c++  java
  • 数位dp:Educational Codeforces Round 53 (Rated for Div. 2) E. Segment Sum

    给出上下界,让你求出其中满足条件:不同的数字的数量不超过k个的数字的总和,答案模998244353,比如123里不同的数字个数为3,113里不同的数字个数为2,111里不同的数字个数为1。

    跟普通的数位dp相比,这道题的不同在于是求总和,不是求数字的个数,但我们可以在求数字个数的基础上再进行求和,以下可以看代码注释。   

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<cmath>
    #include<stack>
    #include<map>
    #include<vector>
    #include<queue>
    #include<set>
    #include<iomanip>
    #include<cctype> 
    #include<ctime>
    using namespace std;
    typedef long long ll;
    #define edl putchar('
    ')
    #define sscc ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
    #define FOR(i,a,b) for(int i=a;i<=b;i++)
    #define ROF(i,a,b) for(int i=a;i>=b;i--)
    #define FORLL(i,a,b) for(ll i=a;i<=b;i++)
    #define ROFLL(i,a,b) for(ll i=a;i>=b;i--)
    #define mst(a) memset(a,0,sizeof(a))
    #define mstn(a,n) memset(a,n,sizeof(a))
    #define zero(x)(((x)>0?(x):-(x))<eps)
    #define si(a) scanf("%d",&a)
    #define sl(a) scanf("%lld",&a)
    #define sd(a) scanf("%lf",&a)
    #define ss(a) scanf("%s",a)
    inline ll gcd(ll a,ll b){return b?gcd(b,a%b):a;}
    inline ll lcm(ll a,ll b){return a/gcd(a,b)*b;}
    int month[15]={0,31,28,31,30,31,30,31,31,30,31,30,31};
    int dir[8][2]={{-1,0},{1,0},{0,-1},{0,1},{-1,-1},{1,1},{1,-1},{-1,1}};
    const int MAXN=2e5+5;
    const int INF=1<<30;
    const long long mod=998244353;
    const double eps=1e-8;
    const ll inff=0x3f3f3f3f3f3f3f3f;
    ll dp[25][1030][12];/*记录答案总和的数组*/
    ll d[25][1030];/*记录答案个数的数组*/
    ll t[25];/*10的幂次方,节省时间*/
    int a[25];/*记录每一位数字*/
    int f[25];/*2的幂次方,节省时间*/
    int k[1030];/*状态压缩,记录某个状态有多少个不同的数字*/
    int p;/*题目问的最大不同数量*/
    struct num
    {
    	ll a,b;/*a对应d数组,b对应dp数组*/
    }s;
    num dfs(int pos,int now,int sta,int limit)
    {
    	if(pos==0)
    	{
    		return (num){1,now};
    	}	
    	if(!limit&&dp[pos][sta][now]!=-1)
    	{
    		return (num){d[pos][sta],dp[pos][sta][now]};
    	}
    	int up=limit?a[pos]:9,g;
    	ll ans=0,cnt=0;
    	FOR(i,0,up)
    	{
    		if(sta==0&&i==0)/*前导0的特殊判断*/ 
    		{
    			s=dfs(pos-1,i,sta,limit&&i==up);
    			cnt+=s.a;/*答案个数*/
    			ans+=s.b;/*答案总和*/
    			cnt%=mod;
    			ans%=mod;
    		}
    		else
    		{
    			g=sta|f[i];
    			if(k[g]<=p)
    			{
    				s=dfs(pos-1,i,g,limit&&i==up);
    				cnt+=s.a;/*答案个数*/
    				ans+=s.b;/*答案总和*/
    				cnt%=mod;
    				ans%=mod;
    			}
    		}	
    	}
    	ans=(ans+cnt*t[pos]%mod*(ll)now%mod)%mod;
    	if(!limit)
    		d[pos][sta]=cnt,dp[pos][sta][now]=ans;
    	return (num){cnt,ans};
    }
    ll solve(ll x)
    {
    	if(x==0) return 0;
        int pos=0;
        while(x)
        {
            a[++pos]=x%10;
            x/=10;
        }
        a[pos+1]=0;
        return dfs(pos,0,0,1).b;
    }
    int main()
    {
        ll n,m;
        f[0]=1,t[0]=1;
        FOR(i,1,18)
        f[i]=f[i-1]*2,t[i]=t[i-1]*10,t[i]%=mod;
        FOR(i,0,1024)
        {
        	int j=i,cnt=0;
        	while(j)
        	{
        		cnt+=j%2;
        		j/=2;
    		}
    		k[i]=cnt;
    	}
        FOR(i,0,20)
        FOR(j,0,1024)
        {
        	d[i][j]=-1;
    	    FOR(I,0,9)
    	    dp[i][j][I]=-1;
    	}
        //scanf("%d",&T);
        //while(1)
        {
        	scanf("%lld%lld%d",&n,&m,&p);
            n=solve(n-1);
            m=solve(m);
    		printf("%lld
    ",(m-n+mod)%mod);
        }
        return 0;
    }
    

      

  • 相关阅读:
    FillForm网页表单填写插件(用于火狐浏览器,自动填表,自动表单,填写表单)
    Firefox下完整读写本地文件的方法
    failure notice
    百度奖品兑换监视程序
    javascript数组及其操作(zz)
    JMETER使用
    ubuntu安装mysql
    windows live writer写csdn博客,very good~
    用SSH在linux下安装JDK和Tomcat
    java模拟HTTP请求(集合了网上搜来的各种)
  • 原文地址:https://www.cnblogs.com/qq936584671/p/9889829.html
Copyright © 2011-2022 走看看