P3581 [POI2015] CZA(状压)

解析

不能在一条思路上死磕!

首先这题真正考的其实就是 p = 3 p=3 p=3
乍一看题意:给出一张特殊图,求哈密顿回路方案数。
然后发现这个图性质不咋地。
然后就不会了。

正解根本和哈密顿回路毛关系也没有!
考虑从1-n依次插入。
注意到,插入i的时候,我们其实只关注i-3,i-2,i-1(不妨称其为“关键元素”)互相之间是否相邻。
实现上,由于有环,所以可能还要记录最左和最右的关键元素是否靠边。
把这个状态状压下来,直接转移即可。
口胡一时爽,实现火葬场。

代码

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define ull unsigned long long
#define debug(...) fprintf(stderr,__VA_ARGS__)
#define ok debug("OK\n")
using namespace std;

const int N=1e6+100;
const int inf=1e9;
const int mod=1e9+7;
inline ll read(){
  ll x(0),f(1);char c=getchar();
  while(!isdigit(c)) {if(c=='-')f=-1;c=getchar();}
  while(isdigit(c)) {x=(x<<1)+(x<<3)+c-'0';c=getchar();}
  return x*f;
}



inline ll ksm(ll x,ll k){
  ll res=1;
  while(k){
    if(k&1) res=res*x%mod;
    x=x*x%mod;
    k>>=1;
  }
  return res;
}

#define add(x,y) (x+=y,x>=mod?x-=mod:0)

int n,m,P;
bool ban[N][10];
int o=5;
struct bruteforce{
  int ans,a[5];
  int vis[5];
  void dfs(int k){
    if(k>n){
      bool flag=1;
      for(int i=1;i<=n;i++){
	if(abs(a[i]-a[i%n+1])>P||ban[a[i]][a[i]-a[i%n+1]+o]) flag=0;
      }
      ans+=flag;
      return;
    }
    for(int i=2;i<=n;i++){
      if(vis[i]) continue;
      a[k]=i;
      vis[i]=1;
      dfs(k+1);
      vis[i]=0;
    }
    return;
  }
  void work(){
    ans=0;
    a[1]=1;
    dfs(2);
    printf("%d\n",ans);
    return;
  }
}bf;
int aa[N];
inline bool check(){
  for(int i=1;i<=n;i++){
    if(abs(aa[i+1]-aa[i])>P) return false;
    if(ban[aa[i]][aa[i]-aa[i+1]+o]) return false;
  }
  return true;
}
void work2(){  
  aa[1]=aa[n+1]=1;
  int p,num=1;
  for(p=2;;p+=2){
    aa[++num]=p;
    if(p==n){
      p--;
      break;
    }
    else if(p==n-1){
      p++;
      break;
    }
  }
  while(p>1){
    aa[++num]=p;
    p-=2;
  }
  int res=0;
  res+=check();
  reverse(aa+2,aa+1+n);
  res+=check();
  printf("%d\n",res);
}
const int bas=4;
inline int Hash(int *x){
  int res=0;
  for(int i=1;i<=3;i++) res=res*bas+x[i];
  return res;
}
int a[5],tmp[10];
int tot,p[N][4],op1[N][3],op2[N][3],tr[N][5],vis[5];
//op1: xiang lin
//op2: kao bian
int id[1050][4][4];
void get(int x,int y){
  ++tot;
  for(int i=1;i<=3;i++) p[tot][i]=a[i];
  op1[tot][0]=(x>>1)&1;op1[tot][1]=x&1;
  op2[tot][0]=(y>>1)&1;op2[tot][1]=y&1;
  id[Hash(a)][x][y]=tot;
  //print(tot);
}
void dfs(int k,int x,int y){
  if(k>3){
    get(x,y);
    return;
  }
  for(int i=1;i<=3;i++){
    if(vis[i]) continue;
    vis[i]=1;
    a[k]=i;
    dfs(k+1,x,y);
    vis[i]=0;
  }
  return;
}
inline int ins(int x,int pos){  
  int num=0;
  int cur[4],cnt=0;
  for(int i=0;i<=3;i++){   
    if(i){
      tmp[++num]=a[i]-1;
    }
    if(i==pos){
      tmp[++num]=3;
    }    
    if(i==0&&!op2[x][0]) tmp[++num]=0;
    if(i==1&&!op1[x][0]) tmp[++num]=0;
    if(i==2&&!op1[x][1]) tmp[++num]=0;
    if(i==3&&!op2[x][1]) tmp[++num]=0; 
  }
  for(int i=1;i<=num;i++){
    if(tmp[i]) cur[++cnt]=i;
  }
  
  int f1(0),f2(0);
  if(cur[1]+1==cur[2]) f1|=2;
  if(cur[2]+1==cur[3]) f1|=1;
  if(cur[1]==1) f2|=2;
  if(cur[3]==num) f2|=1;

  num=0;
  for(int i=0;i<=3;i++){
    if(i){
      if(a[i]>1)tmp[++num]=a[i]-1;
    }
    if(i==pos){
      tmp[++num]=3;
    }
  }
  return id[Hash(tmp)][f1][f2];
}
void solve(int x){
  memcpy(a,p[x],sizeof(p[x]));
  if(op2[x][0]&&op2[x][1]){
    tr[x][0]=ins(x,0);
    tr[x][3]=ins(x,3);
  }
  if(op1[x][0]) tr[x][1]=ins(x,1);    
  if(op1[x][1]) tr[x][2]=ins(x,2);
}
int f[2][150],now,pre;
void init(int k){
  if(k>3){
    f[now][id[Hash(a)][3][3]]=1;
    return;
  }
  for(int i=1;i<=3;i++){
    if(vis[i]) continue;
    vis[i]=1;
    a[k]=i;
    init(k+1);
    vis[i]=0;
  }
  return;
}
inline bool prelink(int x,int pl){
  if(pl==1) return op2[x][0]&&op2[x][1];
  else return op1[x][pl-2];
}
inline bool suflink(int x,int pl){
  if(pl==3) return op2[x][0]&&op2[x][1];
  else return op1[x][pl-1];
}  
void work3(){
  for(int i=0;i<=3;i++){
    for(int j=0;j<=3;j++){
      dfs(1,i,j);
    }
  }
  //debug("tot=%d\n",tot);
  for(int i=1;i<=tot;i++) solve(i);
  now=1;pre=0;
  init(1);
  for(int i=4;i<=n;i++){
    swap(now,pre);
    memset(f[now],0,sizeof(f[now]));
    for(int j=1;j<=tot;j++){
      if(!f[pre][j]) continue;
      a[1]=p[j][1];
      a[2]=p[j][2];
      a[3]=p[j][3];
      int pl=a[1]==1?1:(a[2]==1?2:3);
      for(int k=0;k<=3;k++){
	if(!tr[j][k]) continue;
	int frt= k==pl-1?4:a[(pl+1)%3+1],suf=k==pl?4:a[pl%3+1];
	if(k==0&&pl==3) suf=4;
	if(k==3&&pl==1) frt=4;	
	if(prelink(j,pl)&&ban[i-3+frt-1][frt-1+o]) continue;
	if(suflink(j,pl)&&ban[i-3][1-suf+o]) continue;
	add(f[now][tr[j][k]],f[pre][j]);
	
      }
    }
  }
  ll ans=0;
  for(int i=1;i<=tot;i++){    
    bool flag=1;
    memcpy(a,p[i],sizeof(p[i]));
    for(int j=1;j<=3&&flag;j++){
      int pre=(j+1)%3+1,suf=j%3+1;
      if(prelink(i,j)&&ban[n-3+a[pre]][a[pre]-a[j]+o]){
	flag=0;
      }
      else if(suflink(i,j)&&ban[n-3+a[j]][a[j]-a[suf]+o]){
	flag=0;
      }
    }
    if(flag) add(ans,f[now][i]);
  }
  ans=ans*ksm(n,mod-2)%mod;
  printf("%lld\n",ans);
  return;
}
signed main(){
#ifndef ONLINE_JUDGE
  freopen("a.in","r",stdin);
  freopen("a.out","w",stdout);
#endif
  n=read();m=read();P=read();
  for(int i=1;i<=m;i++){
    int x=read(),y=read();
    if(abs(x-y)<=P) ban[x][x-y+o]=1;
  }
  if(n<=3){
    bf.work();return 0;
  }
  if(P<=1){
    printf("0");return 0;
  }
  else if(P==2){
    work2();return 0;
  }
  else work3();
  return 0;
}
/*
*/
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值