码迷,mamicode.com
首页 > 其他好文 > 详细

[AHOI2009]同类分布

时间:2019-09-25 17:35:52      阅读:102      评论:0      收藏:0      [点我收藏+]

标签:表示   tps   int   math   导致   while   cstring   一个   algo   

洛咕

题意:给出两个数\(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\n",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\n",part(r)-part(l-1));
    return 0;
}

[AHOI2009]同类分布

标签:表示   tps   int   math   导致   while   cstring   一个   algo   

原文地址:https://www.cnblogs.com/PPXppx/p/11586085.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!