一边往数组里放数,一边让前缀 gcd 只会往“更小的约数”走,再用 DP 记录当前前缀 gcd 和已经凑出来的权值,最后看看能不能刚好凑到 x。
void solve(){
int n,m,x;cin>>n>>m>>x;
if(x<n||x>n*m){
cout<<-1<<endl;
return;
}
vvi d(m+1);
for(int i=1;i<=m;++i){
for(int j=1;j<=i;++j){
if(i%j==0){
d[i].push_back(j);
}
}
}
vvi cur(m+1,vi(x+1,0)),nxt(m+1,vi(x+1,0));
vector<vvi> pre(n+1,vvi(m+1,vi(x+1,-1)));
for(int i=1;i<=m;++i){
if(i<=x){
cur[i][i]=1;
pre[1][i][i]=0;
}
}
for(int len=1;len<n;++len){
for(int i=1;i<=m;++i){
for(int j=1;j<=x;++j){
if(!cur[i][j]){
continue;
}
for(int k:d[i]){
int s=j+k;
if(s<=x&&!nxt[k][s]){
nxt[k][s]=1;
pre[len+1][k][s]=i;
}
}
}
}
cur.swap(nxt);
for(int i=1;i<=m;++i){
fill(all(nxt[i]),0);
}
}
int g=-1;
for(int i=1;i<=m;++i){
if(cur[i][x]){
g=i;
break;
}
}
if(g==-1){
cout<<-1<<endl;
return;
}
vi ans(n+1);
int s=x;
for(int len=n;len>=1;--len){
ans[len]=g;
if(len>1){
int p=pre[len][g][s];
s-=g;
g=p;
}
}
for(int i=1;i<=n;++i){
cout<<ans[i]<<" ";
}
cout<<endl;
}

京公网安备 11010502036488号