『比赛』2016弱校联盟十一专场10.5(12点场) Increasing or Decreasing

题目链接:
https://www.bnuoj.com/bnuoj/contest_show.php?cid=8563#problem/101902

题意:就是要你找x<=a的这个数的不严格递增或递减的个数
例如 112233, 123,而312这种就不算.

个人感想:我的想法很简单,就是用数位dp找到 不严格递增的个数+不严格递减的个数-重复的平衡个数(例如111111)遍是答案了,我不知道为什么这里有个问题在于我加了一个 min的判断数据就少了,不知道是不是数据记忆出错还是怎么的我现在也想不通. 我是拍了一下别人代码的一个数据就知道出错了,**我感觉上就是那个min里,**我都不知道怎么少了.好吧我来讲讲我的思路:

dp[i][j][k][l]:代表的是:位数,前一个数字是j,是否为前导0得到的数据(1/0),l代表递增递减的类型.
然后套基本的数位dp即可.

问题:求某位大佬来帮我看看代码憋- -我也不知道那个min哪里错了.加上我感觉没什么太大问题(解决)

ps:昨天晚上想了一想我知道哪里错了,我既然把min设置了,就会出现我后面出现了true,那么代表可以默认地计数,那么久有问题了,例如 694587 .如果我枚举到6 9第2位,我会设置成 65,可是本来这个数已经是69了,那么递减根本就不合法了,所以就会加多了,是差值变小了,所以 后面的 e是不能随便乱改的…

分析:数位dp

AC代码:

/* Author:GavinjouElephant
 * Title:
 * Number:
 * main meanning:
 *
 *
 *
 */


#include <iostream>
using namespace std;
#include <cstdio>
#include <cmath>
#include <cstring>
#include <algorithm>
#include <sstream>
#include <cctype>
#include <vector>
#include <set>
#include <cstdlib>
#include <map>
#include <queue>
//#include<initializer_list>
//#include <windows.h>
//#include <fstream>
//#include <conio.h>
#define MaxN 0x7fffffff
#define MinN -0x7fffffff
#define lson 2*k
#define rson 2*k+1
typedef  long long ll;
const ll INF=0x3f3f3f3f;
const ll maxn=1e5+10;
ll Scan()//读入整数外挂.
{
    ll res = 0, ch, flag = 0;

    if((ch = getchar()) == '-')             //判断正负
        flag = 1;

    else if(ch >= '0' && ch <= '9')           //得到完整的数
        res = ch - '0';
    while((ch = getchar()) >= '0' && ch <= '9' )
        res = res * 10 + ch - '0';
    return flag ? -res : res;
}
 void Out(ll a)    //输出外挂
 {
     if(a>9)
         Out(a/10);
     putchar(a%10+'0');
 }
 ll top;
 ll dig[20];
 ll dp[25][11][2][2];//i 位数,上一位的数字,前导0,递增递减(1/0)
 ll T;
 ll l,r;

 ll dfs(ll pos,ll pre,ll zero,ll type,bool e)
 {
     if(pos==0)return (ll)1;

     if(!e&&dp[pos][pre][zero][type]!=(ll)-1)
        return dp[pos][pre][zero][type];

     ll ans=0;
     if(type)
     {
         ll limi=e?dig[pos]:9;



         for(ll i=0;i<=limi;i++)
         {
             if(i<pre)continue;//-->

             if(zero&&i==0)
             {
                 ans+=dfs(pos-1,0,1,type,e&&i==limi);
             }
             else  ans+=dfs(pos-1,i,0,type,e&&i==limi);
         }

     }
     else
     {
         ll limi=e?dig[pos]:9;
        
         //limi=min(pre,limi);
         //到现在也不知道为什么加上上面的那句话就会数据少了..
         //如果知道的话帮我看看咯...我是外加了-->if才过的
         for(ll i=0;i<=limi;i++)
         {
             if(i>pre)continue;//-->
             if(zero&&i==0)
             {
                 ans+=dfs(pos-1,10,1,type,e&&i==limi);
             }
             else ans+=dfs(pos-1,i,0,type,e&&i==limi);
         }

     }

     if(!e)
     {
         dp[pos][pre][zero][type]=ans;
     }
     return ans;
 }

 ll solve(ll x)
 {
     if(x==0) return 1;
     top=0;
     ll ans=0;
     ll now=0;
     ll temp=x;
     while(x)
     {
         dig[++top]=x%10;
         x/=10;

         now=now*10+1;
     }

     ll de=temp/now+(top-1)*9+1;//平衡的个数

     ans+=dfs(top,0,1,1,true);

     ans+=dfs(top,10,1,0,true);


     return ans-de;

 }
int main()
{


   scanf("%lld",&T);
   memset(dp,-1,sizeof(dp));
   //solve((ll)1000000000000000000);
   while(T--)
   {
       scanf("%lld%lld",&l,&r);
       printf("%lld\n",solve(r)-solve(l-1));

   }

    return 0;
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值