zoukankan      html  css  js  c++  java
  • [CSP校内集训]reverse(数位DP)

    题意

    给一个范围[L,R],求满足(Lleq n leq R)(Lleq rev(n) leq R)(n)的个数,其中(rev(n))表示将(n)翻转((123->321)),多组询问((L,Rleq 2^64-1))

    思路

    长这样的计数问题,没什么悬念考虑数位DP

    只设(f_{i,lim})表示处理到第(i)位是否顶上界似乎不太够,因为在转移过程中还需要知道倒过来的数的状态,所以再用个变量(lim2)记录倒过来的数的状况

    因为从前向后确定数倒过来看是从后向前确定数,所以(lim2)有三个值:比当前上界小,顶上界,暂时大于上界,用(0,1,2)表示

    仅仅这样做并不能很好的处理前缀0的情况(如0001倒过来看会变成1000,但实际上应该为1),所以我还用了一个变量(zer)表示第一个非零数出现的位置

    状态即为(f_{i,lim1,lim2,zer}),一遍数位DP即可求出答案,递归边界返回值为1的条件为(lim2 eq 2) 或 倒过来的限制R的位数比L多1

    本题毒瘤,(L,R)会炸longlong,需要用unsigned longlong来做,随时都需要注意爆边界的情况qwq

    考试的标程都是错的几个意思

    #include<bits/stdc++.h>
    #define Min(x,y) ((x)<(y)?(x):(y))
    #define Max(x,y) ((x)>(y)?(x):(y))
    using namespace std;
    typedef unsigned long long ll;
    int T,t1,t2,d;
    ll L,R,wei[25];
    ll dp[70][23][2][3];//第一个不是0的位置 
    //0:没碰到上界,1:顶上界,2:过上界 
    
    template <class T>
    void read(T &x)
    {
    	char c; int sign=1;
    	while((c=getchar())>'9'||c<'0') if(c=='-') sign=-1; x=c-48;
    	while((c=getchar())>='0'&&c<='9') x=(x<<1)+(x<<3)+c-48; x*=sign;
    }
    int gw(ll x,int w)
    {
    	if(w==20) return 1;
    	return (x/wei[w-1])%10;
    }
    int get_dep(ll x)
    {
    	int ret=0;
    	while(x) {++ret; x/=10;}
    	return ret;
    }
    ll dfs(int stp,int zer,int lim1,int lim2,ll l,ll r)//正数第stp位,第一个非零位置,顶上界,逆向 
    {
    	if(stp==d+1) return ((lim2!=2 || (stp-zer<=19 && zer && r/wei[stp-zer]) )  &&  zer);
    	if(dp[stp][zer][lim1][lim2]!=-1) return dp[stp][zer][lim1][lim2];
    	ll ret=0;
    	int x=gw(l,d-stp+1),y=gw(r,zer?stp-zer+1:1);
    	if(lim1)
    	{
    		int l2,l3=0;
    		for(int i=0;i<=x;++i)
    		{
    			if(i>y) l2=2;
    			else if(i==y) l2=(lim2==2 ? 2 : 1);
    			else l2=0;
    			if(i) l3=stp;
    			ret+=dfs(stp+1,zer?zer:l3,i==x,l2,l,r);
    		}
    	}
    	else
    	{
    		int l2,l3=0;
    		for(int i=0;i<=9;++i)
    		{	
    			if(i>y) l2=2;
    			else if(i==y) l2=(lim2==2 ? 2 : 1);
    			else l2=0;
    			if(i) l3=stp;
    			ret+=dfs(stp+1,zer?zer:l3,0,l2,l,r);
    		}
    	}
    	return dp[stp][zer][lim1][lim2]=ret;
    }
    ll solve(ll L,ll R)//翻转前<=L,翻转后<=R
    {
    	if(!L||!R) return 0;
    	memset(dp,-1,sizeof(dp));
    	d=get_dep(L);
    	return dfs(1,0,1,1,L,R);
    }
    int main()
    {
    	freopen("reverse.in","r",stdin);
    	freopen("reverse.out","w",stdout);
    	read(T);read(t1);read(t2);
    	wei[0]=1;
    	for(int i=1;i<=19;++i) wei[i]=wei[i-1]*10;
    	while(T--)
    	{
    		read(L);read(R);
    		cout<<solve(R,R)+solve(L-1,L-1)-solve(R,L-1)-solve(L-1,R)<<endl;
    	}
    	return 0;
    }
    
  • 相关阅读:
    【Java】通用版URLConnection 带cookie下载PDF等资源文件
    【机器学习】粗糙集(Rough Set Approach)
    【机器学习】随机森林(Random Forest)
    【Python】微博自动抢红包
    sublime text3
    【神经网络】BP反向传播神经网络
    【MLP】多层感知机网络
    【Bayesian】贝叶斯决策方法(Bayesian Decision Method)
    postman常用功能汇总(基础必备)
    apache在linux下安装
  • 原文地址:https://www.cnblogs.com/Chtholly/p/11735111.html
Copyright © 2011-2022 走看看