ZOJ2599 数位统计论文例题

看了论文,又看了别人博客,还是卡了我两天,看来我对字符串的感知能力真是渣....贴个博客造(bao)福(fu)社会。总结一下

把问题先分析清楚,然后充分预处理,会使后面的过程很简单。

字典序在位数相等的情况下可以转换成大小序。

注意别忽视空串,也就是null。

注意首位能否为0。

另外有个有意思的地方.. vector容器太厉害了...比如直接比较v1<v2是比较v1和v2的字典序。又比如partial_sum、accumulate函数。

代码(http://blog.watashi.ws/1213/andrew-stankevich-6-solution/ZOJ2599/  这个NB.. 我贴的代码是为了以后自己复习的...参考了链接里的代码..)

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
using namespace std;
long long se[20][200];
long long sl[20][200];
long long le[200][20];
long long ll[200][20]; 
void Init()
{
    long long i,j,k;
    memset(se,0,sizeof(se));
    memset(sl,0,sizeof(sl));
    se[0][0]=1,le[0][0]=1;
    for(i=1;i<20;++i)
        for(j=0;j<200;++j)
        {
            for(k=0;k<10;++k)
                if(j-k>=0)
                    se[i][j]+=se[i-1][j-k];
            le[j][i]=se[i][j];
        }
    for(i=0;i<20;++i)
    {
        sl[i][0]=0;
        for(j=1;j<200;++j)
            sl[i][j]=sl[i][j-1]+se[i][j-1];
    }
    for(i=0;i<200;++i)
    {
        ll[i][0]=0;
        for(j=1;j<20;++j)
            ll[i][j]=ll[i][j-1]+le[i][j-1];
    }
}
long long SumLess(vector<int>& n,long long sum)
{
    long long i,j,tmp=0,ans=0;
    for(i=0;i<n.size();++i)
        tmp+=n[i];
    if(tmp<sum)
        ans++;
    for(i=0;i<n.size();++i)
    {
        for(j=0;j<n[i];++j)
            if(sum-j>=0)
                ans+=sl[n.size()-i-1][sum-j];
        sum-=n[i];
        if(sum<0)
            break;
    }
    return ans-1;
}
long long LexLess(vector<int>& n,long long sum,vector<int>& k)
{
    long long i,j,ans=0,tmp=sum,sum2=0;
    for(i=0;i<k.size();++i)
    {
        if(sum==0)
            ans++;     
        for(j=(i==0?1:0);j<k[i];++j)
            if(sum>=j)
            {
                ans+=ll[sum-j][n.size()-i-1];
            }
        sum-=k[i];
        if(sum<0)
            break;
    }
    sum=tmp;
    if(k<=n)
    {
        for(i=0;i<k.size();++i)
        {
            for(j=(i==0?1:0);j<k[i];++j)
                if(sum>=j)
                    ans+=le[sum-j][n.size()-i-1];
            sum-=k[i];
            if(sum<0)
                break;
        }
    }
    else
    {
        for(i=0;i<n.size();++i)
        {
            for(j=(i==0?1:0);j<n[i];++j)    
                if(sum>=j)
                    ans+=le[sum-j][n.size()-i-1];
            sum-=n[i];
            if(sum<0)
                break;
        }
        if(sum==0)   
            ans++;
    }    
    return ans;
}
long long Work1(vector<int>& n,vector<int>& k)
{
    long long i,sum=0;
    for(i=0;i<k.size();++i)
        sum+=k[i];
    return SumLess(n,sum)+LexLess(n,sum,k)+1;
}
long long Work2(vector<int>& n,long long k)
{
    long long l=1,r=200,mid,ret,sum,i,j;
    while(l!=r)
    {
        mid=((l+r)>>1)+1;
        if(SumLess(n,mid)<k)
            l=mid;
        else
            r=mid-1;
    }
    sum=l;
    k-=SumLess(n,sum);
    k--;
    vector<int> ans;
    ans.clear();
    while(ans.size()<n.size())
    {
        ans.push_back(9);
        while(ans.back()>=0&&LexLess(n,sum,ans)>k)
        {
            ans.back()--;   
        }
        if(ans.back()<0)
            break;
    }
    if(ans.back()<0)
        ans.pop_back();
    ret=0;
    for(i=0;i<ans.size();++i)
        ret=ret*10+ans[i];
    return ret;
}
vector<int> ToVector(long long n)
{
    vector<int> v;
    while(n)
    {
        v.push_back(n%10);  
        n/=10;
    }
    reverse(v.begin(),v.end());
    return v;
}
int main()
{
    vector<int> nv,kv;
    long long n,k;
    Init();
    while(cin>>n>>k)
    {
        if(n==0&&k==0)
            break;
        nv=ToVector(n);
        kv=ToVector(k);
        cout<<Work1(nv,kv)<<" ";
        cout<<Work2(nv,k)<<endl;
    }
    return 0;
}  


 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值