zoukankan      html  css  js  c++  java
  • 数位dp 51nod1623

    题目:www.51nod.com/onlineJudge/questionCode.html#!problemId=1623

    题意描述看起来有点怪怪的,描述有一定错误,不过看了示例操作就知道要干什么了。

    知道是数位dp,但是是之前没有做过的类型,而且题目的规则要仔细分析。

    1.      对于一连串先递增再递减(先递减再递增)的数字,操作数为其中不同数字的个数。

    如:12392 出现了1,2,3,9 操作数为4,所以要有一个状态数统计出现的数字,那么使用2进制统计即可。

    结论:每出现一个状态数中没有出现的数字,将其加入状态数,并使操作数+1。

    2.      对于多个情况 1复合的数字,很难直观的看出规律,先列几个例子:

    13542 操作数为5  135423 操作数为6  1354234 操作数为7

    13542343 操作数为7  135423434 操作数为8

    这是一个很难总结的结论,看了别人的博客才总结出来,感觉一般情况下太难想到了。

    结论:每新增加一个数字,就将状态数中比其大的数字除去。

    结合之前得出的结论,就是这道题的解题思路了。

    用之前的例子演示一下:

    1 状态数1 操作数1

    13 状态数13 操作数2

    135 状态数135 操作数3

    1354 状态数134 操作数4

    13542 状态数12 操作数5

    135423 状态数123 操作数6

    1354234 状态数1234 操作数7

    13542343 状态数123 操作数7

    135423434 状态数1234 操作数8

    由此得到了无关递增递减的一般化规则

    在操作上,用或(|)操作添加状态,用与(&)操作消除比其大的数

    实际写起来操作很简单,是一道锻炼思维的好题

    #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<stack>
    using namespace std;
    const int MAXN=6e5+5;
    const int INF=1<<30;
    const long long mod=1e9+7;
    const double eps=1e-8;
    #define ll long long
    #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)
    ll dp[20][1050][20],l,r,k;
    int a[20],b[15],c[15];
    void init()
    {
    	b[0]=0;
    	b[1]=1;
    	c[0]=0;
    	FOR(i,2,10)
    	b[i]=b[i-1]*2;
    	FOR(i,1,9)
    	c[i]=b[i+1]-1;
    	FOR(i,0,18)
    	FOR(j,0,c[9])
    	FOR(k,0,18)
    	dp[i][j][k]=-1;
    }
    ll dfs(int pos,int m,int kk,int limit)
    {
    	//cout<<pos<<" "<<m<<" "<<kk<<" "<<limit<<endl;
    	if(pos==0)
    	{
    		return kk==k;
    	}
    	if(!limit&&dp[pos][m][kk]!=-1)
    	{
    		return dp[pos][m][kk];
    	}	
    	int up=limit?a[pos]:9;
    	ll ans=0;
    	FOR(i,0,up)
    	{
    		if(m&b[i])//如果已经有了数字i,则消除高位,操作数不增加
    		ans+=dfs(pos-1,(m&c[i]),kk,limit&&i==up);
    		else//如果没有数字i,则消除高位,操作数增加
    		ans+=dfs(pos-1,(m&c[i])|b[i],kk+(i!=0),limit&&i==up);//如果i是0,则不计入操作数
    	}
    	if(!limit)
    		dp[pos][m][kk]=ans;
    	return ans;
    }
    ll solve(ll x)
    {
        int pos=0;
        while(x)
        {
            a[++pos]=x%10;
            x/=10;
        }
        a[pos+1]=0;
        return dfs(pos,0,0,1);
    } 
    int main()
    {
    	init();
    	cin>>l>>r>>k;
    	cout<<solve(r)-solve(l-1)<<endl;
    }
    

      

  • 相关阅读:
    Paper Pal:一个中英文论文及其代码大数据搜索平台
    45天闭门刷题,精通这份Java高级架构面试文档,入职阿里涨薪20K
    三面阿里云计算,出门我就哭了!(Java研发岗,还原真实“被虐”场景)
    “TensorFlow 开发者出道计划”全攻略,玩转社区看这里!
    什么是可串行化MVCC
    2021最新Spring全家桶集合:SpringBoot+SpringCloud+Spring源码
    2015到2021的阿里JAVA架构技术演进,Alibaba架构师到底有多牛逼?
    大厂面试果然名不虚传,蚂蚁三面凉经,真的是“太难了”
    三面阿里云计算,出门我就哭了!(Java研发岗,还原真实“被虐”场景)
    Dubbo 一些你不一定知道但是很好用的功能
  • 原文地址:https://www.cnblogs.com/qq936584671/p/9272970.html
Copyright © 2011-2022 走看看