1 条题解

  • 0
    @ 2025-8-24 21:17:51

    自动搬运

    查看原文

    来自洛谷,原作者为

    avatar miyachn
    with New_Void||关我可得2号回关(私信喵!||城南花已开

    搬运于2025-08-24 21:17:51,当前版本为作者最后更新于2025-07-15 23:04:31,作者可能在搬运后再次修改,您可在原文处查看最新版

    自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多

    以下是正文


    题目传送门


    一道非常好的深搜优化题
      暴力算法$$ O(nq) $$,由于数据比较水所以加一些优化能够过,上一篇题解关于暴力的讲解已经很清晰了,所以这里不在过多赘述了
      Q:如何优化?
      考虑提前预处理出所有符合要求的数,按照常规暴力思想依旧是枚举每一个数,但是这样太慢了
      那么我们换个思路,将判断可行性转化为构造可行的数
      这里就用到 dfs 来构造啦(具体解释都放在注释里了)

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    ll a1[6]={0,2,5,6,8,9};
    ll a2[6]={0,2,5,9,8,6};
    //a1储存所有翻转后有意义的数字
    //a2储存a1中的数字翻转后的结果 
    ll Q,l,r,p[20];
    vector<ll> q;//记录所有符合题意的数 
    void dfs(ll len,ll ori,ll rev){
    	//ori表示当前计算的一段翻转后有意义的数串
    	//rev表示ori翻转后的结果 
    	//len记录当前ori和rev的长度 
    	if(len) q.push_back(ori*p[len]+rev);//两端拼起来符合要求 
    	ll st;
    	if(len==7) return;//长度达到限制了!(最大不超过10^14 
    	if(len==0) st=1;//不能有前导0
    	else st=0;
    	for(int i=st;i<6;++i){
    		if(a1[i]==a2[i]) q.push_back(ori*p[len+1]+a1[i]*p[len]+rev);//可以放在两端中间 
    		dfs(len+1,ori*10+a1[i],a2[i]*p[len]+rev);//变换前和变换后的两个数放在两个数串中间也可以 
    	}
    }
    int main(){
    	p[0]=1;
    	for(int i=1;i<=15;i++) p[i]=p[i-1]*10;//预处理10的次方 
    	dfs(0,0,0);//构造所有可行解 
    	sort(q.begin(), q.end());//排序 为后面的二分做准备 
    	cin>>Q;
    	while(Q--){
    		cin>>l>>r;
    		ll ans=upper_bound(q.begin(),q.end(),r)-lower_bound(q.begin(),q.end(),l);
    		//使用二分查找能够很好地降低复杂度 
    		cout<<ans<<endl;
    	}
    	return 0;
    }
    

    无注释版本:

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    ll a1[6]={0,2,5,6,8,9};
    ll a2[6]={0,2,5,9,8,6};
    ll Q,l,r,p[20];
    vector<ll> q; 
    void dfs(ll len,ll ori,ll rev){
    	if(len) q.push_back(ori*p[len]+rev); 
    	ll st;
    	if(len==7) return; 
    	if(len==0) st=1; 
    	else st=0;
    	for(int i=st;i<6;++i){
    		if(a1[i]==a2[i]) q.push_back(ori*p[len+1]+a1[i]*p[len]+rev); 
    		dfs(len+1,ori*10+a1[i],a2[i]*p[len]+rev); 
    	}
    }
    int main(){
    	p[0]=1;
    	for(int i=1;i<=15;i++) p[i]=p[i-1]*10; 
    	dfs(0,0,0); 
    	sort(q.begin(), q.end()); 
    	cin>>Q;
    	while(Q--){
    		cin>>l>>r;
    		ll ans=upper_bound(q.begin(),q.end(),r)-lower_bound(q.begin(),q.end(),l);
    		cout<<ans<<endl;
    	}
    	return 0;
    }  
    
    • 1

    信息

    ID
    6731
    时间
    1000ms
    内存
    128MiB
    难度
    3
    标签
    递交数
    0
    已通过
    0
    上传者