首页 > 其他分享 >reverse 题解

reverse 题解

时间:2024-07-04 17:19:41浏览次数:21  
标签:pw int 题解 len llt operatorname reverse

reverse 题解

注意到本题数据范围较大且与数位有关,考虑数位 DP 。

我们发现对于每个询问,我们可以将第一个条件拆开之后差分,可以先从后往前 DP ,预处理出末尾满足 $ L \le \operatorname{reverse}(n) \le R $ 的个数,之后使用试填法填数即可。具体地,在预处理时,处理出顶到上界,顶到下界,以及必定满足 $ L \le \operatorname{reverse}(n) \le R $ 的方案数,不妨假定 \(L\)和\(R\)位数相等。

显然因为我们是从后向前 DP ,所以假如有一个填法满足

\[L_{k} \le \operatorname{reverse}(n)_{k} \le R_{k},L_{k+1,len} = \operatorname{reverse}(n)_{k+1,len} or \operatorname{reverse}(n)_{k+1,len} = R_{k+1,len} \]

在填到 \(k\) 时,无论后面如何填,一定满足 $ L \le \operatorname{reverse}(n) \le R $,反之如果

\[L_{k} \ge \operatorname{reverse}(n)_{k}or \operatorname{reverse}(n)_{k}\ge R_{k},L_{k+1,len} = \operatorname{reverse}(n)_{k+1,len} or \operatorname{reverse}(n)_{k+1,len} = R_{k+1,len} \]

那么无论后面填什么,一定不满足题意

考虑进行分讨,对于每个 \(k\) 分别处理 \(L_{k,len} = \operatorname{reverse}(n)_{k,len}\),\(R_{k,len} = \operatorname{reverse}(n)_{k,len}\),\(L_{k,len} \le \operatorname{reverse}(n)_{k,len} \le R_{k,len}\) 三种情况的方案数,显然前两种都是\(1\),最后一种是 \(R_{k,len}-L_{k,len}-1\),边界情况自行特判,这根本不用进行 DP,我们可以直接 \(O(len)\) 预处理

填数的时候,根据已经填的几位数reverse之后和 \(L\),\(R\) 的后几位大小关系,确定哪些情况是正确的,如果满足大于等于 \(L\),则可以取到上述第一种情况,满足小于等于 \(R\),则可以取到上述第二种情况。至此,我们完成了对位数相同的 \(L\),\(R\) 的计算。

对于位数不相同的情况,为了避免前导零的干扰,我们可以枚举可能的每个位数计算,这个算法复杂度 \(O(Tu\log^2 L)\) ,其中 \(u\) 是采用的进制,这里取 \(10\)。

代码:

#include <bits/stdc++.h>
#define llt unsigned long long
using namespace std;
llt t,a,b,pw[21],dp[22][5],pre[22],len,la,lb;
llt get(llt x,llt index){if(index<1||index>20)	return 0;return x/pw[index-1]%10;}
llt get_head(llt x,llt index){return x/pw[index-1];}
llt Q(llt now){llt cnt=0;while(now){now/=10,cnt++;}return cnt;}
void DP(llt L,llt R)
{
	llt u,l,r;
	memset(pre,0,sizeof(pre));
    memset(dp,0,sizeof(dp));
	dp[0][0]=0-1;dp[0][1]=dp[0][2]=1;
	for(int i=1;i<=len;i++)
	{
		l=get(L,len-i+1);r=get(R,len-i+1);
		dp[i][0]=get_head(R,len-i+1)-get_head(L,len-i+1)-1;
		dp[i][1]=dp[i][2]=1;
	}
}
llt GET(llt p,llt L,llt R)
{
	llt u,l,r,sum=0,now=0,now1,now2,last1=2,last2=2,tot=0; 
	for(int i=len;i>=1;i--)
	{
		u=get(p,i);l=get(L,len+1-i),r=get(R,len+1-i);
		for(int j=0;j<u;j++)
		{
			if(sum==0&&j==0)	continue;
			if(j<l) now1=1;
            if(j==l)    now1=last1;
            if(j>l) now1=2;
            if(j<r) now2=2;
			if(j==r)    now2=last2;
            if(j>r) now2=1;
            tot+=dp[i-1][0];
            if(now1==2) tot+=dp[i-1][1];
            if(now2==2) tot+=dp[i-1][2];
		}
		if(u<l) last1=1;
        if(u==l)    last1=last1;
        if(u>l) last1=2;
        if(u<r) last2=2;
		if(u==r)    last2=last2;
        if(u>r) last2=1;
		sum+=u;
	}
	return tot;
}
void work(llt L,llt R)
{
	llt maxx=Q(R),to=Q(L),x,y,ans=0;
	for(int i=maxx;i>=to;i--)
	{
		len=i;
		if(i==maxx)	x=R;else	x=pw[i]-2,ans++;
		if(i==to)	y=L;else	y=pw[i-1];
		DP(L,x);ans+=GET(x+1,L,x)-GET(y,L,x);
	}
	printf("%llu\n",ans);
}
int main() 
{
	#ifdef LOCAL
		freopen("1.in","r",stdin);
		freopen("1.out","w",stdout);
	#endif
	pw[0]=1;for(int i=1;i<=20;i++)	pw[i]=pw[i-1]*10;	
	scanf("%llu%llu%llu",&t,&a,&b);
	while(t--)
	{
		scanf("%llu%llu",&a,&b);
        if(b+1==0)  b--;//为了避免炸ull,在MAX_ull不可能取到情况下的特判
		work(a,b);
	}
	return 0;
}

为了通过加强版数据,我们需要继续优化复杂度,首先我们发现 GET 里面对于 \(j\) 的枚举完全可以避免,接着又发现中间的 \(l\),\(r\) 都是 \(10^k\) 和 \(10^{k+1}-1\) ,此时因为 \(R\) 的位数比我们多一位,所以只剩下 \(L\) 的限制,所有 \(len\) 位(包含前导零)大于等于 \(L\) 且没有末尾零的数翻转过来都是一个合法的数,直接累加答案就好了,GET 只需要跑两次,复杂度 \(O(T\log R)\),可以通过加强版数据。

代码:

#include <bits/stdc++.h>
#define llt unsigned long long
#define Il __always_inline
using namespace std;
llt seed,last,pw[21],b,a;int t,len;
Il int Q(llt now){int cnt=0;for(;now;now/=10,++cnt);return cnt;}
Il llt GET(llt p,llt L,llt R)
{
	int u,l,r,last1=2,last2=2;llt tot=0; 
	for(int i=len;i>=1;--i)
	{
		u=p/pw[i-1]%10;l=L/pw[len-i]%10,r=R/pw[len-i]%10;
		if(last1==2&&l<u)	++tot;
		if(last2==2&&r<u)	++tot;	
		if(u>l+1)	tot+=u-l-1;
		tot+=min(r,u);
		tot+=(R/pw[len-i+1]-L/pw[len-i+1]-1)*(u-1);
		if(u<l) last1=1;
        else if(u>l) last1=2;
        if(u<r) last2=2;
        else if(u>r) last2=1;
	}
	return tot;
}
Il void work(llt L,llt R)
{
	int maxx=Q(R),to=Q(L);
	llt x,y,ans=0;
	for(int i=maxx;i>=to;--i)
	{
		len=i;
		if(i==maxx)	x=R;else	x=pw[i]-2,++ans;
		if(i==to)	y=L;else	y=pw[i-1];
        if(i!=maxx&&i!=to)  ans+=x-y+1-(L-L/10)+(L%10!=0);
		else ans+=GET(x+1,L,x)-GET(y,L,x);
	}
	printf("%llu\n",ans);
}
int main() 
{
	#ifdef LOCAL
		freopen("1.in","r",stdin);
		freopen("std.out","w",stdout);
	#endif
	pw[0]=1;for(register int i=1;i<=19;++i)	pw[i]=pw[i-1]*10;
	pw[20]=0-1;	
	scanf("%llu%llu%llu",&t,&a,&b);
	while(t--)
	{
		scanf("%llu%llu",&a,&b);
        if(b+1==0)  b--;
		work(a,b);
	}
	return 0;
}

标签:pw,int,题解,len,llt,operatorname,reverse
From: https://www.cnblogs.com/hzoi-wang54321/p/18284251

相关文章

  • Kithara常见问题解答
    目录通用问题我的内核驱动程序已经签名了吗?是否可以在打开驱动程序时防止显示介绍窗口?Windows7仍然支持吗?错误0x10142422(`KSERROR_CANNOT_START_KERNEL`)在`KS_openDriver`时出现?错误10145241(KSERROR_CANNOT_START_KERNEL)在KS_openDriver时出现?可以在C#应用程......
  • javascript url 传递参数中文乱码问题解决方案
    在JavaScript中,传递URL参数时,如果参数包含中文字符,可能会出现乱码问题。解决这一问题可以使用encodeURIComponent和decodeURIComponent函数。这些函数会对URL参数进行编码和解码,确保特殊字符(包括中文字符)能够被正确传递和解析。以下是一个完整的解决方案示例: 1.......
  • [JLU] 数据结构与算法上机题解思路分享-
    前言首先,请务必自己尽全力尝试实现题目,直接看成品代码,思维就被拘束了,也很容易被查重。这里只是思路解析的博客,代码仓库在JLU_Data_Structures_Record希望你能在这里找到你想要的:)第三次上机A手撕BST分数50作者朱允刚单位吉林大学对一棵初始为空的二叉查找树(Binary......
  • 牛客小白月赛97 A-D题解
    AAAAAAAAAAAAAAAAAAAAA-----------------------------题解-------------------------------------------统计数组中有没有出现三个相同的边即可点击查看代码#include<bits/stdc++.h>usingnamespacestd;intmain(){intn;cin>>n;map<int,int>m;int......
  • P2286 [HNOI2004] 宠物收养场 题解
    P2286[HNOI2004]宠物收养场set做法题链\(_{洛谷}\)\(_{题库}\)思路一眼查找前驱后继的题。注意到一句话:那么用set就没有什么阻碍了,方便又快捷。题意很简单,若宠物多则查找与人需求最接近的上下两个值,人多则找与宠物最接近的上下两个人的值。出题人很善良,把选人和选宠物......
  • 刺杀 题解
    题目简述你在玩一个游戏,需要刺杀\(n\)个敌人。可以肉搏或者用子弹击杀敌人。肉搏第\(i\)个敌人会使你的体力值减少\(x_i\),你要保证你的体力值始终非负。击杀第\(i\)个敌人后,会获得\(y_i\)颗子弹,有可能\(y_i\)为\(0\),这时候你啥都拿不到。你初始体力值为\(s\),有一个......
  • P10589 题解
    经典题。tag:数状数组。开一个权值树状数组,从左往右遍历,统计左边比\(y_i\)小的数字个数\(ul_i\)与比\(a_i\)大的数字个数\(dl_i\);然后从右往左遍历,统计右边比\(y_i\)小的数字个数\(dr_i\)与比\(a_i\)大的数字个数\(ur_i\)。两个答案即为\(\sum_{i=1}^ndl_i\cdo......
  • CSP-S 2005 T1 谁拿了最多奖学金【题解】
    1.题目描述某校的惯例是在每学期的期末考试之后发放奖学金。发放的奖学金共有五种,获取的条件各自不同:院士奖学金,每人 8000 元,期末平均成绩高于 80 分(>80),并且在本学期内发表1篇或1篇以上论文的学生均可获得;五四奖学金,每人 4000 元,期末平均成绩高于 85 分(>85),并且班级......
  • 历年CSP-J初赛真题解析 | 2018年CSP-J初赛选择题(1-15)
    学习C++从娃娃抓起!记录下CSP-J备考学习过程中的题目,记录每一个瞬间。附上汇总贴:历年CSP-J初赛真题解析|汇总_热爱编程的通信人的博客-CSDN博客第1题以下哪一种设备属于输出设备()A.扫描仪B.键盘C.鼠标D.打印机【答案】:D【解析】A、B、C都是输入设备第2题下列......
  • P7690 [CEOI2002] A decorative fence 题解
    题目传送门前置知识计数DP解法方案数统计同luoguP2467[SDOI2010]地精部落,但部分写得不太好看的状态转移方程在本题中并不适用,但仍可借鉴其“离散化”思想。考虑试填。设\(f_{i,j,0/1}\)表示用\(i\)块不同的木板构成栅栏,其中最左边的木板的长度从小到大排在第\(j\)......