P11460 题解
最优的最小差值为
若
下面考虑
以此类推可以发现,第
下面考虑更一般的情形,即如果
以此类推,在放完左侧的空位之前,每一对点都只能放在
具体应该如何计算呢?有一些区间 dp 之类的方法,但难以优化到线性。考虑枚举区间中最后剩余空位的位置,则对于这个空位左边所有剩余的点,如果它的值已经被确定了,则和它同一组的点所处的位置也被确定了。并且可以得知的信息是“在放置这一组时,其左边已经被放了多少组数,右边已经被放了多少组数”。
于是现在的问题被转化为:有若干个数,每个数可以选择左右两个方向。还有若干个限制,每个限制形如“在前
但直接实现还是需要枚举空位,复杂度
因此如果
综上所述,先枚举
赛时代码(由于是从暴力改过来的,写的非常混乱,仅供参考)
#include <bits/stdc++.h>
#define INF 1000000000
#define LINF 1000000000000000000
#define mod 1000000007
#define F first
#define S second
#define ll long long
#define N 2010
using namespace std;
int ksm(int x,int y){
int ret=1;
while(y>0){
if(y&1) ret=(1ll*ret*x)%mod;
x=(1ll*x*x)%mod;
y>>=1;
}
return ret;
}
int n,m,p[N],q[N],C[N][N],ans,sz;
pair<int,pair<int,int> > seq[N];
bool check(vector<int> per){
for(int i=0;i<n;i++) if(p[i]!=-1&&p[i]!=per[i]) return false;
return true;
}
bool isok(int x,int y){
if(p[x]!=-1&&p[x]!=y) return false;
if(q[y]!=-1&&q[y]!=x) return false;
return true;
}
int calc1(int mid){
if(!isok(mid-1,0)) return 0;
if(!isok(mid+1,n-1)) return 0;
int ret=1;
sz=0;
for(int i=1;i<n/2;i++){
if(q[i]==-1&&q[i+n/2]==-1) continue;
if(q[i]!=-1){
if(q[i]<mid&&(q[i]&1)) return 0;
if(q[i]>mid&&(!(q[i]&1))) return 0;
}
if(q[i+n/2]!=-1){
if(q[i+n/2]>mid&&(q[i+n/2]&1)) return 0;
if(q[i+n/2]<mid&&(!(q[i+n/2]&1))) return 0;
}
if(q[i]!=-1){
if(q[i+n/2]!=-1&&q[i+n/2]!=q[i]+1) return 0;
if(q[i]<mid) seq[sz++]=make_pair(i,make_pair(0,(mid-q[i])/2));
else seq[sz++]=make_pair(i,make_pair(1,(n-q[i])/2));
}
else{
if(q[i+n/2]<mid) seq[sz++]=make_pair(i,make_pair(0,(mid-q[i+n/2]+1)/2));
else seq[sz++]=make_pair(i,make_pair(1,(n-q[i+n/2]+1)/2));
}
}
for(int i=0;i<=sz;i++){
int sx,sy,tx,ty;
sx=(i==0?0:(seq[i-1].S.F==0?seq[i-1].S.S:seq[i-1].F-seq[i-1].S.S));
sy=(i==0?0:(seq[i-1].S.F==1?seq[i-1].S.S:seq[i-1].F-seq[i-1].S.S));
tx=(i==sz?mid/2:(seq[i].S.F==0?seq[i].S.S-1:seq[i].F-seq[i].S.S));
ty=(i==sz?(n-mid)/2-1:(seq[i].S.F==1?seq[i].S.S-1:seq[i].F-seq[i].S.S));
if(tx<sx||ty<sy||sx<0||sy<0||tx<0||ty<0) return 0;
ret=(1ll*ret*C[tx-sx+ty-sy][tx-sx])%mod;
}
return ret;
}
int val[N][2][2],num[N][2][2],bel[N],idx[N],seq0[N];
int getvl(int mid){
if(mid==0) return 1;
sz=0;
for(int i=1;i<=(mid-1)/2;i++){
if(q[i]!=-1){
if(q[i]>mid) return 0;
if(q[i]%2==0) return 0;
}
if(q[i+n/2]!=-1){
if(q[i+n/2]>mid) return 0;
if(q[i+n/2]&1) return 0;
}
if(q[i]!=-1||q[i+n/2]!=-1) seq0[sz++]=i;
}
for(int i=0;i<sz;i++) for(int c=0;c<2;c++){
num[i][c][0]=-1,num[i][c][1]=-1;
if(c==0){
int x;
if(q[seq0[i]]!=-1){
if(q[seq0[i]+n/2]!=-1&&q[seq0[i]+n/2]!=q[seq0[i]]-1) continue;
x=q[seq0[i]];
}
else x=q[seq0[i]+n/2]+1;
num[i][0][0]=x/2+1,num[i][0][1]=seq0[i]-num[i][0][0];
}
else{
int x;
if(q[seq0[i]]!=-1){
if(q[seq0[i]+n/2]!=-1&&q[seq0[i]+n/2]!=q[seq0[i]]+1) continue;
x=q[seq0[i]];
}
else x=q[seq0[i]+n/2]-1;
num[i][1][1]=(mid-x)/2,num[i][1][0]=seq0[i]-num[i][1][1];
}
}
for(int i=0;i<sz;i++) for(int cx=0;cx<2;cx++) for(int cy=0;cy<2;cy++){
val[i][cx][cy]=0;
if(i==0&&cx) continue;
if(i==sz&&cy) continue;
int sx,sy,tx,ty;
if(i==0) sx=sy=0;
else sx=num[i-1][cx][0],sy=num[i-1][cx][1];
tx=num[i][cy][0]-(cy==0),ty=num[i][cy][1]-(cy==1);
if(tx>=sx&&ty>=sy&&sx>=0&&sy>=0&&tx>=0&&ty>=0) val[i][cx][cy]=C[tx-sx+ty-sy][tx-sx];
}
int num0=0,pro=1,ret=0;
for(int i=0;i<sz;i++){
idx[seq0[i]]=i;
bel[i]=0;
if(val[i][0][0]==0) num0++;
else pro=(1ll*pro*val[i][0][0])%mod;
}
for(int i=mid-2;i>=0;i-=2){
if(isok(i,n/2+mid/2)&&(!num0)){
int sx=(sz==0?0:num[sz-1][bel[sz-1]][0]);
int sy=(sz==0?0:num[sz-1][bel[sz-1]][1]);
int tx=i/2,ty=(mid-i)/2-1;
if(tx>=sx&&ty>=sy&&sx>=0&&sy>=0&&tx>=0&&ty>=0) ret=(1ll*ret+1ll*pro*C[tx-sx+ty-sy][tx-sx])%mod;
}
if(i==0) break;
if(p[i]!=-1||p[i-1]!=-1){
int x;
if(p[i]!=-1&&p[i-1]!=-1){
if(p[i]!=p[i-1]+n/2) break;
x=p[i-1];
}
else if(p[i]!=-1) x=p[i]-n/2;
else x=p[i-1];
x=idx[x];
if(bel[x]==0){
if(val[x][x==0?0:bel[x-1]][bel[x]]==0) num0--;
else pro=(1ll*pro*ksm(val[x][x==0?0:bel[x-1]][bel[x]],mod-2))%mod;
if(x+1<sz){
if(val[x+1][bel[x]][bel[x+1]]==0) num0--;
else pro=(1ll*pro*ksm(val[x+1][bel[x]][bel[x+1]],mod-2))%mod;
}
bel[x]=1;
if(val[x][x==0?0:bel[x-1]][bel[x]]==0) num0++;
else pro=(1ll*pro*val[x][x==0?0:bel[x-1]][bel[x]])%mod;
if(x+1<sz){
if(val[x+1][bel[x]][bel[x+1]]==0) num0++;
else pro=(1ll*pro*val[x+1][bel[x]][bel[x+1]])%mod;
}
}
}
}
return ret;
}
int getvr(int mid){
if(mid==n-1) return 1;
vector<int> cur;
for(int i=0;i<n;i++) cur.push_back(p[i]);
reverse(p,p+n);
for(int i=0;i<n;i++) if(p[i]>=0) p[i]=n-p[i]-1;
for(int i=0;i<n;i++) q[i]=-1;
for(int i=0;i<n;i++) if(p[i]>=0) q[p[i]]=i;
int ret=getvl(n-mid-1);
for(int i=0;i<n;i++) q[i]=-1;
for(int i=0;i<n;i++){
p[i]=cur[i];
if(p[i]>=0) q[p[i]]=i;
}
return ret;
}
int calc2(int mid){
if(mid&&(!isok(mid-1,0))) return 0;
if(mid<n-1&&(!isok(mid+1,n-1))) return 0;
return (1ll*getvl(mid)*getvr(mid))%mod;
}
void solve(){
for(int i=0;i<n;i++) if(isok(i,n/2)) ans=(ans+(i&1?calc1(i):calc2(i)))%mod;
return;
}
int main(){
for(int i=0;i<N;i++){
C[i][0]=1;
for(int j=1;j<=i;j++) C[i][j]=(C[i-1][j-1]+C[i-1][j])%mod;
}
int T;
scanf("%d%d",&T,&n);
while(T--){
scanf("%d",&m);
for(int i=0;i<n;i++) p[i]=q[i]=-1;
for(int i=0;i<m;i++){
int x,y;
scanf("%d%d",&x,&y);
p[x]=y,q[y]=x;
}
if(n%2==0){
vector<int> per(n);
for(int i=0;i<n;i++) per[i]=(i&1?0:n/2)+i/2;
ans=0;
if(check(per)) ans++;
reverse(per.begin(),per.end());
if(check(per)) ans++;
printf("%d\n",ans);
continue;
}
ans=0;
solve();
for(int i=0;i<n;i++) q[i]=-1;
for(int i=0;i<n;i++) if(p[i]>=0) p[i]=n-p[i]-1,q[p[i]]=i;
solve();
printf("%d\n",ans);
}
return 0;
}