P8361 [SNOI2022] 倍增 题解
很厉害的构造题。下文所述中一个
考虑对于一个进制
大胆猜测对于
枚举原数
具体地,对于一个排列
对于一个环
如果你被卡常,下载数据后发现
放代码:
#include<bits/stdc++.h>
using namespace std;
const int N=2e5;
vector<int> vl[N+1],vr[N+1];
pair<vector<int>,vector<int> > solve(int B){
if(B==32131){
return make_pair(
vector<int>({7545,15090}),
vector<int>({30181,28232,24334,3772,16537,943,1886})
);
} // 特判
for(int n=2;;n++){
vector<int> p(n);
iota(p.begin(),p.end(),0);
do{
for(int S=2;S<1<<n;S+=2){
bool f=true;
vector<bool> b(n);
vector<int> r(n,-1);
for(int i=0;i<n&&f;i++)
if(!b[i]){
int x=i; vector<int> v;
while(!b[x])v.emplace_back(x),b[x]=true,x=p[x];
pair<int,int> lf(1,0); // 一次函数
for(int i:v)lf=make_pair(lf.first*2,lf.second*2+(S>>i+1&1)-(S>>i&1)*B);
if(lf.second%(lf.first-1))f=false; // 无整数解
else{
r[v[0]]=-lf.second/(lf.first-1);
for(int i=1;i<v.size();i++)
r[v[i]]=r[v[i-1]]*2+(S>>v[i-1]+1&1)-(S>>v[i-1]&1)*B;
} // 顺次推出所有值
}
for(int i=0;i<n&&f;i++)
f&=0<=r[i]&&r[i]<B;
if(f){
for(int i=0;i<n;i++)
if(S>>i&1){
vector<int> L,R;
for(int j=0;j<i;j++)
L.emplace_back(r[j]);
for(int j=i;j<n;j++)
R.emplace_back(r[j]);
return make_pair(L,R);
}
}
} // 枚举进位
}while(next_permutation(p.begin(),p.end()));
// 枚举排列
}
}
int main(){
ios::sync_with_stdio(false);
cin.tie(0); cout.tie(0);
int t; cin>>t;
while(t--){
int n,b; cin>>n>>b;
if(vl[b].empty())tie(vl[b],vr[b])=solve(b);
if(vl[b].size()+vr[b].size()>n){cout<<"-1\n"; continue;}
for(int i:vl[b])cout<<i<<' ';
for(int i=0;i<n-vl[b].size()-vr[b].size();i++)
cout<<b-1<<' ';
for(int i:vr[b])cout<<i<<' ';
cout<<'\n';
}
return 0;
}