細かいところが詰められず…。
https://yukicoder.me/problems/no/3271
問題
正整数N,Kが与えられる。
1~NのPermutation P,Qのうち、内積がKとなるようにできるか。
できるなら一例を示せ。
解法
Pを昇順に固定し、Qを考える。
内積の最小値はQを降順にした時、最大値は昇順にした時である。
また、Nが4以上なら、最小値~最大値の間はどの値も構築できる。
このことから、Pを定めQを先頭から定める際、未使用の値のうち最小値か最大値のいずれかを入れよう。
その際、残ったP,Qで狙ったKが作れるほうを取って行けばよい。
未確定の要素が4個以下となったら総当たりすればよい。
int N; ll K; int P[202020]; vector<int> ret[5][31]; ll ma[202020],mi[202020]; void solve() { int i,j,k,l,r,x,y; string s; cin>>N>>K; for(i=1;i<=200000;i++) { ma[i]=1LL*i*(i+1)*(2*i+1)/6; mi[i]=1LL*i*(i+1)*(i+2)/6; } if(K<mi[N]||K>ma[N]) { cout<<"No"<<endl; return; } for(i=1;i<=4;i++) { vector<int> V; FOR(j,i) V.push_back(j+1); do { int sum=0; FOR(j,i) { sum+=(j+1)*V[j]; } ret[i][sum]=V; } while(next_permutation(ALL(V))); } if(N<=4) { if(ret[N][K].empty()) { cout<<"No"<<endl; } else { cout<<"Yes"<<endl; FOR(i,N) cout<<ret[N][K][i]<<" "; cout<<endl; FOR(i,N) cout<<i+1<<" "; cout<<endl; } return; } int L=1,R=N; for(i=N;i>=5;i--) { ll a=1LL*i*(i+1)/2; if(K-a>=mi[i-1]&&K-a<=ma[i-1]) { K-=a; P[N-i]=R--; continue; } a=1LL*i*i; assert(K-a>=mi[i-1]&&K-a<=ma[i-1]); K-=a; P[N-i]=L++; } FOR(i,4) P[N-4+i]=ret[4][K][i]+L-1; cout<<"Yes"<<endl; FOR(i,N) cout<<P[i]<<" "; cout<<endl; FOR(i,N) cout<<i+1<<" "; cout<<endl; }
まとめ
段々狭めていくのは思いつけたのに…。