「CMOI R1」mex1 题解
Grand_Dawn · · 题解
mex1 题解
checker
解决该问题,知道如何写 checker 是必要的。
首先,如果
又可以发现相同的数字之间没有区别,所以可以设
如果不选取
如果选取了至少一个
而对于选取非
而且又有这些子集共有
因此可以在
性质
显然以上的过程是唯一确定的,可以认为是一种递推过程。
即可以定义
递推式:
边界条件:
如果采用递推可以获得
优化下界
可以发现很多记忆化数组中很多的答案都是
可以发现,当
初始时先令
若加入
若加入
因此若加入
因此证明完毕,构造仅需采用
实际上,下界仅需要设定为
优化上界
可以发现有以下性质:如果
证明:如果
那么对于
对于
而
因此答案会变大。使用冒泡排序可证明以上性质。
因此使用拆分数暴力枚举可以确定上确界。
实际上,上界仅需要设定为
#include<bits/stdc++.h>
#define N 35
#define INF 2000000009
using namespace std;
void write(int x){
if(x>9)write(x/10);
putchar(x%10+'0');
}
int pw[N],mx[N];
template<class first,class second,int C>
struct Unordered_map{
struct node{
first t;
second w;
int nxt;
}e[C+9];
int tot,hd[C+9];
int hash(first x){
return x%C;
}
second& operator [](first a){
int x=hash(a);
for(int i=hd[x];i;i=e[i].nxt){
if(e[i].t==a)return e[i].w;
}
e[++tot].t=a;
e[tot].nxt=hd[x];
hd[x]=tot;
return e[tot].w;
}
second find(first a){
int x=hash(a);
for(int i=hd[x];i;i=e[i].nxt){
if(e[i].t==a)return e[i].w;
}
return -1;
}
};
Unordered_map<int,char,300009>mp[N];
int check(int x,int n){
if(x==0)return 1;
if(x>mx[n])return 0;
if(mp[n].find(x)!=-1)return mp[n][x];
if(x<pw[n])return 0;
for(int i=1;i<=n;i++){
if(x%(pw[i]-1))continue;
if(check(x/(pw[i]-1)-pw[n-i],n-i))return mp[n][x]=i;
}
return mp[n][x]=0;
}
void solve(){
int x;cin>>x;
for(int n=1;pw[n-1]<=x+1;n++)
if(check(x,n)){
int id=0;
write(n);putchar('\n');
while(x){
int pos=mp[n][x];
for(int i=pos;i>=1;i--)write(id),putchar(' ');
x=x/(pw[pos]-1)-pw[n-pos];
n-=pos;id++;
}
for(int i=n;i>=1;i--)write(id+1),putchar(' ');
putchar('\n');
return;
}
puts("-1");
}
int b[39];
int calc(){
int c=0;while(b[c])c++;
int ans=0,cnt=0;
while(c>0){
ans=(ans+pw[cnt])*(pw[b[--c]]-1);
cnt+=b[c];
}
return ans;
}
int dfs(int x,int lft,int lst=1000000000){
if(lft==0)return calc();
int ans=0;
for(int i=min(lft,lst);i>=1;i--){
b[x]=i;
ans=max(ans,dfs(x+1,lft-i,i));
b[x]=0;
}
return ans;
}
int main(){
//freopen("10-1.in","r",stdin);
//freopen("a.out","w",stdout);
pw[0]=1;for(int i=1;i<=31;i++)pw[i]=pw[i-1]*2;pw[32]=INF;
for(int i=1;i<=31;i++){
if(i<=28)mx[i]=dfs(0,i);
else mx[i]=INF;
}
for(int i=1;i<=32;i++)
for(int j=i-1,tmp=0;j>=0&&tmp<=INF;j--){
tmp+=pw[j];
mp[i][tmp]=i-j;
}
int t;cin>>t;
while(t--)solve();
return 0;
}