1. 程式人生 > >正睿 2019 省選附加賽 Day1 T1 考考試

正睿 2019 省選附加賽 Day1 T1 考考試

比較奇怪的一個列舉題。
注意到10=2*5,所以10^k的二進位制表示一定恰好在末尾有k個0。
考慮從小到大去填這個十進位制數。
填的時候記錄一下當前的二進位制表示。
每次嘗試去填0或者10^k。
如果要填下一位的時候發現它的二進位制表示已經為1的話,停止擴充套件。
因為:
如果這一位填0,由於後面填的數末尾的0>k不會影響這一位,無法是其與二進位制字尾相同。
如果這一位填1,必然產生進位,同理,也無法與其二進位制字尾相同。
考慮這樣做的複雜度。
考慮每一個答案。把它擴展出來最多利用了k步中間狀態,k為其長度,加上高精度的複雜度,最終複雜度為O(nk^2)。

#include<iostream>
#include<cctype>
#include<cstdio>
#include<cstring>
#include<string>
#include<cmath>
#include<ctime>
#include<cstdlib>
#include<algorithm>
#define N 22000
#define L 2200
#define eps 1e-7
#define inf 1e9+7
#define ll long long
using namespace std;
inline int read()
{
    char ch=0;
    int x=0,flag=1;
    while(!isdigit(ch)){ch=getchar();if(ch=='-')flag=-1;}
    while(isdigit(ch)){x=(x<<3)+(x<<1)+ch-'0';ch=getchar();}
    return x*flag;
}
struct big
{
    int len,a[L];
    big()
    {
        len=1;
        memset(a,0,sizeof(a));
    } 
    void print()
    {
        for(int i=len;i>=1;i--)printf("%d",a[i]);
    }
};
big operator+(big a,big b)
{
    big ans;
    ans.len=max(a.len,b.len);
    for(int i=1;i<=ans.len;i++)
    {
        ans.a[i]+=a.a[i]+b.a[i];
        ans.a[i+1]+=(ans.a[i]>>1);
        ans.a[i]&=1;
    }
    if(ans.a[ans.len+1])ans.len++;
    return ans;
}
big operator*(big a,int b)
{
    big ans=a;
    for(int i=1;i<=ans.len;i++)ans.a[i]*=b;
    for(int i=1;i<=ans.len;i++)
    {
        ans.a[i+1]+=ans.a[i]>>1;
        ans.a[i]&=1;
    }
    while(ans.a[ans.len+1])
    {
        ans.len++;
        ans.a[ans.len+1]+=ans.a[ans.len]>>1;
        ans.a[ans.len]&=1;
    }
    return ans;
}
big k,v,q[N],f[N];
int main()
{   
    int n=read(),i,l=1,r=1,t=1,cnt=0,tot=1;
    k.a[1]=v.a[1]=1;q[1].a[1]=0;f[1].a[1]=0;
    for(;;l=r+1,r=tot,t++)
    {
        for(i=l;i<=r;i++)
        if(!q[i].a[t])q[++tot]=q[i],f[tot]=f[i];
        for(i=l;i<=r;i++)
        if(!q[i].a[t])
        {
            q[++tot]=q[i]+k;f[tot]=f[i]+v,cnt++;
            if(cnt==n){f[tot].print();return 0;}
        }
        v=v*2;k=k*10;
    }
    return 0;
}