zoukankan      html  css  js  c++  java
  • [AHOI2009]同类分布

    洛咕

    题意:给出两个数(l,r),求出([l,r])中各位数字之和能整除原数的数的个数.((1<=l<=r<=10^{18}))

    分析:刚开始普普通通地套模板,过了样例,以为写的是对的,结果只有10分.也不知道哪里思路出了问题.

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    #include<cmath>
    #include<queue>
    #include<map>
    #include<set>
    #define ll long long
    using namespace std;
    inline ll read(){
        ll x=0,o=1;char ch=getchar();
        while(ch!='-'&&(ch<'0'||ch>'9'))ch=getchar();
        if(ch=='-')o=-1,ch=getchar();
        while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();
        return x*o;
    }
    int len,a[20];ll dp[20][20][200];
    inline ll dfs(int pos,int pre,ll sum1,ll sum2,int lead,int limit){
    	if(pos>len){
    		if(!sum2)return 1;
    		if(sum1%sum2==0)return 1;
    		return 0;
    	}
    	if(dp[pos][pre][sum2]!=-1&&!lead&&!limit)return dp[pos][pre][sum2];
    	ll cnt=0;int res=limit?a[len-pos+1]:9;
    	for(int i=0;i<=res;++i){
    		if((!i)&&lead)cnt+=dfs(pos+1,0,0,0,1,limit&&(i==res));
    		else if(i&&lead)cnt+=dfs(pos+1,i,i,i,0,limit&&(i==res));
    		else cnt+=dfs(pos+1,i,1ll*sum1*10+i,sum2+i,0,limit&&(i==res));
    	}
    	return !lead&&!limit?dp[pos][pre][sum2]=cnt:cnt;
    }
    inline ll part(ll x){
    	len=0;while(x)a[++len]=x%10,x/=10;
    	memset(dp,-1,sizeof(dp));
    	return dfs(1,0,0,0,1,1);
    }
    int main(){
    	ll l=read(),r=read();
    	printf("%lld
    ",part(r)-part(l-1));
        return 0;
    }
    

    后来看了一下题解,(get)了一种极其奇妙的解法:枚举模数!!!因为(dfs)过程中我们得到的原数是在(long) (long)范围内的,数组下标显然装不下(我上面那份代码都没考虑到把原数装进数组的一维,应该是错在这里,导致每次结果偏大??).

    考虑枚举所有的各位数字之和作为模数(mod)((1)~(9*len),(len)表示数字的位数),然后搜索过程中,设原数为(st),各位数字之和为(sum),原数(st)可以一边对当前枚举到的(mod)取模,所以就可以装进数组下标了.每搜索出一个数,如果(st==0)&&(sum==mod)就是一个合法的数.

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    #include<cmath>
    #include<queue>
    #include<map>
    #include<set>
    #define ll long long
    using namespace std;
    inline ll read(){
        ll x=0,o=1;char ch=getchar();
        while(ch!='-'&&(ch<'0'||ch>'9'))ch=getchar();
        if(ch=='-')o=-1,ch=getchar();
        while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();
        return x*o;
    }
    int len,mod,a[20];ll ans,dp[20][200][200];
    inline ll dfs(int pos,int st,int sum,int lead,int limit){
    //把普通模板中记录上一位填数的pre删掉了,因为它在本题中没有任何意义
    	if(pos>len)return (!st&&sum==mod);//判断该数是否合法
    	if(dp[pos][st][sum]!=-1&&!lead&&!limit)return dp[pos][st][sum];
    	ll cnt=0;int res=limit?a[len-pos+1]:9;
    	for(int i=0;i<=res;++i){
    		if((!i)&&lead)cnt+=dfs(pos+1,0,0,1,limit&&(i==res));
    		else if(i&&lead)cnt+=dfs(pos+1,i%mod,i,0,limit&&(i==res));
    		else cnt+=dfs(pos+1,(st*10+i)%mod,sum+i,0,limit&&(i==res));
    	}
    	return lead&&limit?cnt:dp[pos][st][sum]=cnt;
    }
    inline ll part(ll x){
    	ans=0;len=0;while(x)a[++len]=x%10,x/=10;
    	for(mod=1;mod<=9*len;++mod){//枚举模数
    		memset(dp,-1,sizeof(dp));
    		ans+=dfs(1,0,0,1,1);
    	}
    	return ans;
    }
    int main(){
    	ll l=read(),r=read();
    	printf("%lld
    ",part(r)-part(l-1));
        return 0;
    }
    
  • 相关阅读:
    mysql 按天创建分区存储过程
    Logstash下载安装使用并日志写入Mysql数据库
    开源BI分析工具Metabase配置与完全使用手册
    MySQL安装之yum安装
    IDEA创建SpringBoot
    JDK环境变量配置
    MySQL存储过程
    定时执行任务
    fastjson的使用——JSON字符串、JSON对象、Java对象的互转
    SQL反模式读书笔记思维导图
  • 原文地址:https://www.cnblogs.com/PPXppx/p/11586085.html
Copyright © 2011-2022 走看看