【Baltic2014】【BZOJ3917】Sequence

Description

序列A由从N开始的连续K个数按顺序构成,现在将A中的每个数只保留某一个数码,记为序列B,给定K和B,求可能的最小的N
Input

第一行一个数K,第二行K个数B_i
Output

输出一个数N
Sample Input

6

7 8 9 5 1 2
Sample Output

47
HINT

K<=100000,0<=B_i<=9

N是正整数

Source

APIO强行给此题打广告啊….
此题智商题,我确实不会做
提供一份英文版的官方题解,自己看吧

We’ll solve our task by solving a more complex task first: for each i-th sequence element we’ll declare sequence A_i.
A_i is the sequence of digits which i-th sequence element has to have.
For our initial task, A_i = {d_i}, where d_i - …

Lets donate N = (X)y, where y = N mod 10 is the last digit and X = N div 10.
Now we have to try all possible y values (0, 1, …, 9).
After we have locked y value with one of possible values, our sequence looks like this: (X)y, (X)y+1, …, (X)8, (X)9, (X+1)0, (X+1)1 …, (X+1)8, (X+1)9, (X+2)0, …
After removing last digit, we get sequence X, …, X, X+1, …, X+1, X+2, …

What digits does X has to have?
(X)y has A_1, so X must have A_1 \ {y}. (X)(y+1) has A_2, so X must have A_2 \ {y+1} and so on.

By merging these requirements, we can get a new sequence of sets B_1, B_2, …
B_1 declares required digits for X, B_2 - for (X+1) and so on.
We repeat the same steps with our new sequence.
What happens when we repeat these steps?
We started with sequence length K, so after first step our new sequence length will be not bigger than [K/10]+1.
So after log K steps our sequence will be of length 1 or 2 - at this step we can produce the answer.

Time complexity: O(K*log K)

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#define MAXN 100010
#define LL long long
#define GET (ch>='0'&&ch<='9')
using namespace std;
int k,b[MAXN];
template <class classname>
inline void in(classname &x)
{
    char ch=getchar();x=0;
    while (!GET)    ch=getchar();
    while (GET) x=x*10+ch-'0',ch=getchar();
}
LL solve(const int a[],int n,bool fla)
{
    LL ret=1ll<<62;
    if (n==1)
    {
        ret=0;
        for (int i=1;i<=9;++i)
            if (a[1]&(1<<i))
            {
                ret=ret*10+i;
                if (ret==i&&(a[1]&1))   ret*=10;
            }
        if (ret==0&&(a[1]&1))   ret=10;
        return ret;
    }
    int tn[MAXN],tp=0;
    for (int i=0;i<9+fla;++i)
    {
        int num=0,now=i;tp=0;bool b=0;
        for (int j=1;j<=n;++j)
        {
            num|=a[j]&(1023-(1<<now));
            if ((a[j]&1)&&now==0)   b=1;
            now++;now=now>=10?now-10:now;
            if (!now||j==n) tn[++tp]=num,num=0;
        }
        LL ans=solve(tn,tp,i<9||n>2)*10+i;
        if (!ans&&b)    ans=10;
        ret=min(ret,ans);
    }
    return ret;
}
int main()
{
    in(k);
    for (int i=1;i<=k;i++)  in(b[i]),b[i]=1<<b[i];
    cout<<solve(b,k,1)<<endl;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值