牛客6—— Easy Construction (思维+构造)
题意:
能否构造一个1~n的排列,使得对于任意的 i (1<=i<=n) ,排列都存在一个长度为i的子区间的和%n==k。
思路:
先考虑无解的情况,当i==n时,子区间只有一种情况,元素的和为1+2+……+n,即sum=n*(n+1)/2。如果sum%n!=k的话,说明一定无解。
当n为奇数时,sum%n=0,这时候k=0,可以构造排列:n,1,n-1,2,n-2……
这样除了首项,偶数项+下一个奇数项的和为n,所以就可以当i为奇数时,从首项开始选;当i为偶数时,从第二项开始选。
当n为偶数时,sum%n=n/2,即k=n/2,可以构造排列:n,n/2,1,n-1,2,n-2……
这样从第三项开始,奇数项和下一个偶数项的和为n,所以当i为奇数时,从n/2开始选;当i为偶数时,从n开始选。
代码:
#pragma GCC optimize("Ofast,no-stack-protector,unroll-loops,fast-math") #pragma GCC target("sse,sse2,sse3,ssse3,sse4.1,sse4.2,avx,avx2,popcnt,tune=native") #pragma GCC optimize(2) #include<bits/stdc++.h> using namespace std; #define ll long long #define I_int ll typedef pair<int,int> PII; inline ll read() { ll x=0,f=1;char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();} return x*f; } char F[200]; inline void out(I_int x) { if (x == 0) return (void) (putchar('0')); I_int tmp = x > 0 ? x : -x; if (x < 0) putchar('-'); int cnt = 0; while (tmp > 0) { F[cnt++] = tmp % 10 + '0'; tmp /= 10; } while (cnt > 0) putchar(F[--cnt]); //cout<<" "; } const int maxn=1e6+7; int a[maxn]; int main(){ int n=read(),k=read(); if((n*(n+1)/2)%k){ puts("-1"); return 0; } if(n&1){ a[1]=n; for(int i=2,cnt=1;i<=n;i+=2,cnt++){ a[i]=cnt;a[i+1]=n-cnt; } } else{ a[1]=n;a[2]=n/2; for(int i=3,cnt=1;i<=n;i+=2,cnt++){ a[i]=cnt;a[i+1]=n-cnt; } } for(int i=1;i<=n;i++) out(a[i]),putchar(' '); return 0; }