除草(3.30~4.4)

1、travel

基本把樹剖忘光了。。。

注意到b樹上的點至多對應a樹上的一個點,詢問要求b樹上的一條路徑對應a樹上幾條路徑。

簡單的說就是把樹上的路徑剖成logn段,每段我們都可以利用主席樹對每段查詢即可。

#include 
#include 
#include 
#include 

using namespace std;
const int Maxn=100005;
#define pb push_back
int W1[Maxn],W2[Maxn],W[Maxn*2],size[Maxn],q[Maxn];
int fa[Maxn],dep[Maxn],DEP[Maxn],sum[Maxn*20],top[Maxn];
int num[Maxn],nw[Maxn],stk[Maxn],v[Maxn*2],val[Maxn];
int son[Maxn*20][2],FA[Maxn][20],T[Maxn];
int n,m,Q,i,j,tot,l,r,cnt,x,u1,v1,u2,v2,ans,st,Z;
vector  e1[Maxn],e2[Maxn];

void read(){
  tot=0;
  for (i=1;i<=n;i++) e1[i].clear();
  for (i=2;i<=n;i++){
    scanf("%d",&x);
    e1[x].pb(i);
    e1[i].pb(x);
  }
  for (i=1;i<=n;i++){
    scanf("%d",&W1[i]);
    W[++tot]=W1[i];
  }
  
  scanf("%d",&m);
  for (i=1;i<=m;i++) e2[i].clear();
  for (i=2;i<=m;i++){
    scanf("%d",&x);
  	e2[x].pb(i);
  	e2[i].pb(x);
  }
  for (i=1;i<=m;i++){
    scanf("%d",&W2[i]);
    W[++tot]=W2[i];
  }
}

bool cmp(const int &a,const int &b)
 { return size[a]>size[b]; }

void Find_Heavy_Edge(){
  for (q[l=r=1]=1,dep[1]=1;l<=r;l++){
  	int len=e1[q[l]].size();
  	for (i=0;i0;r--){
  	size[q[r]]++;
  	if (fa[q[r]]==0) continue;
  	size[fa[q[r]]]+=size[q[r]];
  }
  
  for (i=1;i<=n;i++) top[i]=i;
  for (l=1;l<=n;l++){
  	x = q[l];
  	if (e1[x].empty()) continue;
    sort(e1[x].begin(),e1[x].end(),cmp);
    int len=e1[x].size();
    for (i=0;i0){
  	x=stk[T];
  	int len=e1[x].size();
  	for (nw[x]++;nw[x]>1;
  if (mid>=x) ins(son[p][0],son[q][0],l,mid,x);
    else ins(son[p][1],son[q][1],mid+1,r,x);
}

void Make_Tree(){
  memset(FA,0,sizeof(FA));
  for (q[l=r=1]=1,DEP[1]=1;l<=r;l++){
  	int len=e2[q[l]].size();
  	for (i=0;im) return;
    }

  memset(T,0,sizeof(T));
  for (i=1,st=0;i<=m;i++){
  	x=q[i];
  	if (val[x]==0) T[x] = T[ FA[x][0] ];
      else ins(T[ FA[x][0] ],T[x],1,n,val[x]);
  }
}

void work(){
  Discretization();
  Find_Heavy_Edge();
  Connect_Heavy_Edge();
  Correspond();
  Make_Tree();
}

int LCA(int x,int y){
  if (DEP[x]=0;i--)
    if (DEP[FA[x][i]]>=DEP[y])
      x=FA[x][i];
  for (int i=16;i>=0;i--)
    if (FA[x][i]!=FA[y][i])
      x=FA[x][i], y=FA[y][i];
  if (x==y) return x;
  return FA[x][0];
}

int Query(int p1,int p2,int p3,int p4,int l,int r,int L,int R){
  if (l>R || L>r) return 0;
  if (L<=l && R>=r) return sum[p1]+sum[p2]-sum[p3]-sum[p4];
  int mid=(l+r)>>1;
  int ret1=Query(son[p1][0],son[p2][0],son[p3][0],son[p4][0],l,mid,L,R);
  int ret2=Query(son[p1][1],son[p2][1],son[p3][1],son[p4][1],mid+1,r,L,R);
  return ret1+ret2;
}

void solve(){
  scanf("%d",&Q);
  ans=0;
  while (Q--){
  	scanf("%d%d%d%d",&u1,&v1,&u2,&v2);
  	u1^=ans; v1^=ans; u2^=ans; v2^=ans;
  	ans=dep[u1]+dep[v1]+DEP[u2]+DEP[v2];
 	Z=LCA(u2,v2);
  	ans-=DEP[Z]*2-1;
  	while (true){
	  if (top[u1]==top[v1]){
	  	int x1=min(num[u1],num[v1]), x2=max(num[u1],num[v1]);
	  	ans-=Query(T[u2],T[v2],T[Z],T[ FA[Z][0] ],1,n,x1,x2);
	  	break;
	  } else
	  {
	  	if (dep[ top[u1] ]

2、弗洛伊德的復仇

可以看到如果所有的邊都滿足ai>bi(應該是優惠吧微笑),那麼一定存在最優策略使得所有的貨物都應該是選擇一條路徑來運輸。

但是題目裏給了一條邊ai<bi(這隻鴿子似乎很討厭大量的工作難過。。。),我們可能仍是選擇上一種方案,或者可能選擇一部分來給這隻另類的鴿子運(注意這隻鴿子運輸的貨物應爲ai),其他的給另外的運,不難搞出大概的方案如下:


我們會得到三個圖,各種求求最短路即可,最後枚舉兩個中點即可

(考場上居然忘了特判無解丟了好些分。。。。)

#include 
#include 
#include 

using namespace std;
const int Maxn=10005, INF=1e9;
int node[Maxn],next[Maxn],a[Maxn],len[Maxn];
int Ds[Maxn],Dt[Maxn],q[100000],d1[105][105],d2[105][105];
int x[Maxn],y[Maxn],z1[Maxn],z2[Maxn],z3[Maxn];
int i,j,k,n,m,S,T,fw,tot,l,r,ans;
bool v[Maxn];

void add(int x,int y,int z){
  node[++tot]=y; next[tot]=a[x]; a[x]=tot; len[tot]=z;
  node[++tot]=x; next[tot]=a[y]; a[y]=tot; len[tot]=z;
}

void spfa(int S,int d[],int K){
  for (i=1;i<=n;i++) d[i]=INF;
  d[S]=0; v[S]=1;
  for (q[l=r=1]=S;l<=r;v[q[l++]]=0){
  	for (i=a[q[l]];i;i=next[i])
  	if ( ((i&1)==K) && d[node[i]]>d[q[l]]+len[i]){
  	  d[node[i]] = d[q[l]]+len[i];
  	  if (!v[node[i]]) v[ q[++r]=node[i] ]=1;
    }
  }
}

int main(){
  freopen("G.in","r",stdin);
  freopen("G.out","w",stdout);
  scanf("%d%d%d%d%d",&n,&m,&S,&T,&fw);
  S++; T++;
  int flag=0;
  for (i=1,tot=0;i<=m;i++){
  	scanf("%d%d%d%d%d",&x[i],&y[i],&z1[i],&z2[i],&z3[i]);
  	x[i]++; y[i]++;
  	if (z1[i]=fw) add(x[i],y[i],z1[i]*fw);
  	  else add(x[i],y[i],z1[i]*z3[i]+z2[i]*(fw-z3[i]));
  }
  spfa(S,Ds,1);
  spfa(T,Dt,0);
  if (flag>0){
  	int t=z3[flag];
  	
  	memset(d1,127/2,sizeof(d1));
  	for (i=1;i<=n;i++) d1[i][i]=0;
  	for (i=1;i<=m;i++)
  	  if (z3[i]>=t) d1[x[i]][y[i]] = min( d1[x[i]][y[i]], z1[i]*t );
  	    else d1[x[i]][y[i]] = min( d1[x[i]][y[i]], z1[i]*z3[i]+z2[i]*(t-z3[i]) );
  	    
  	for (k=1;k<=n;k++)
  	  for (i=1;i<=n;i++) if (i!=k)
  	     for (j=1;j<=n;j++)
  	     if (i!=j && k!=j && d1[i][j]>d1[i][k]+d1[k][j])
  	       d1[i][j] = d1[i][k]+d1[k][j];
     
    memset(d2,127/2,sizeof(d2));
  	for (i=1;i<=n;i++) d2[i][i]=0;
  	for (i=1;i<=m;i++){
  	  if (i==flag) continue;
  	  if (z3[i]>=fw-t) d2[x[i]][y[i]] = min( d2[x[i]][y[i]], z1[i]*(fw-t) );
  	    else d2[x[i]][y[i]] = min( d2[x[i]][y[i]], z1[i]*z3[i]+z2[i]*( (fw-t)-z3[i] ) );
  	}
  	    
    for (k=1;k<=n;k++)
  	  for (i=1;i<=n;i++) if (i!=k)
  	     for (j=1;j<=n;j++)
  	     if (i!=j && k!=j && d2[i][j]>d2[i][k]+d2[k][j])
  	       d2[i][j] = d2[i][k]+d2[k][j];
    
    ans=1000000000;
    for (i=1;i<=n;i++)
      for (j=1;j<=n;j++)
      if (d1[i][j]<100000000 && d2[i][j]<100000000)
        ans=min(ans, Ds[i]+d1[i][j]+d2[i][j]+Dt[j]);
    if (ans>100000000)  puts("Impossible");
  	  else printf("%d\n",ans);
	       
  } else
  {
  	if (Ds[T]>100000000)  puts("Impossible");
      else printf("%d\n",Ds[T]);
  }
  return 0;
}

3、無盡之懲

把矩陣應用到bsgs裏驚訝

我們可以把題目裏的變換改成一個矩陣A。

題目裏就是要求最小的k滿足a*A^k=b,很明顯的bsgs。

(不要搞啥A矩陣的逆矩陣,完全可以靠逆向模擬把b向前變換微笑

#include 
#include 
#include 
#include 

using namespace std;
typedef unsigned UI;
int a[50],b[50],c[50],t1[50],t2[50];
int s1,s2,i,j,k,t;
UI n,N,M,tmp,x,K[70000],KK[70000];

struct Matrix
{
  int a[33][33];
  void init(){
  	memset(a,0,sizeof(a));
  	for (i=0;i<33;i++)
  	  a[i][i]=1;
  }
  Matrix operator *(const Matrix &x)const
  {
	Matrix ret;
	UI column[33], row[33];
	for (int i=0;i<33;i++){
	  column[i] = row[i] = 0;
	  for (int j=0;j<32;j++){
	  	if (a[i][j]) column[i] |= ((UI)1<0;n>>=1){
  	if (n&1) ret=ret*A;
  	A=A*A;
  }
  return ret;
}

void Baby_Step_Giant_Step(){
  N = 1<0;i--)
  	  b[i] = b[i-1];
  	b[0] = x;
  	for (i=0,x=0;iM) {puts("poor sisyphus");return;}
  for (i=0;i<=M;i++)
  if (K[i]==tmp){
  	printf("%u\n",(UI)k*M+i);
  	break;
  }
}

int main(){
  freopen("punish.in","r",stdin);
  freopen("punish.out","w",stdout);
  while (~scanf("%u%d%d",&n,&s1,&s2)){
    read();
	init();
	Baby_Step_Giant_Step();
  }
  return 0;
}

4、迴文超能力

求字符串每向後加入一個字符會產生多少新迴文串

——長知識了,原來有一個叫做迴文樹的東西,簡直就是處理迴文串的利器得意

(不會的同學可以去UOJ博客裏找相關論文)

(有了這個東西APIO2014T1就變成模板題了吐舌頭

#include 
#include 
#include 

using namespace std;
const int Maxn=5000005;
char S[Maxn],ans[Maxn];
int son[Maxn][2],fail[Maxn],len[Maxn];
int n,last,i,st,x,cur,nw;

int newnode(int x){
  son[st][0] = son[st][1] = 0;
  len[st] = x;
  return st++;
}

void init(){
  gets(S+1);
  n=strlen(S+1);
  S[0]='#';
  newnode( 0 );
  newnode( -1 );
  fail[0] = 1;
  last = 0;
}

int get_fail(int x,int n){
  while ( S[n-len[x]-1]!=S[n] ) x=fail[x];
  return x;
}

int main(){
  freopen("palin.in","r",stdin);
  freopen("palin.out","w",stdout);
  init();
  for (i=1;i<=n;i++){
  	x = S[i]-'a';
  	cur = get_fail( last, i );
  	if ( !son[cur][x] ){
  	  ans[i]='1';
  	  nw = newnode( len[cur]+2 );
  	  fail[nw] = son[ get_fail( fail[cur], i ) ][x];
  	  son[cur][x] = nw;
  	} else ans[i]='0';
  	last = son[cur][x];
  }
  puts(ans+1);
  return 0;
}

5、艾瑪與乘積之和

又遇FFT,跪爛的節奏。

求n個數中任意k個數的乘積之和。

觀察這個式子(1+a1*x)*(1+a2*x)*.....*(1+an*x),x^k前的係數就是k的答案。。。。

直接求的話複雜度是O(n^2)。把整個式子分成兩部分,這樣不停地分治下去,用FFT合併,這樣就可以做到大約O(nlogn)

#include 
#include 
#include 
#include 

using namespace std;
const int Maxn=30005;
const int Mod=100003;
typedef long double LD;
int d[16][2][Maxn<<1];
int a[Maxn],ans[Maxn],i,n,q,x;
struct CP
{
  LD x, y;
  CP operator +(const CP &a)const
    { return (CP){x+a.x, y+a.y}; }
  CP operator -(const CP &a)const
    { return (CP){x-a.x, y-a.y}; }
  CP operator *(const CP &a)const
    { return (CP){x*a.x-y*a.y, x*a.y+y*a.x}; }
}  A[Maxn<<2], B[Maxn<<2];

void FFT(CP A[],int N,int flag){
  for (int i=1,j=0;i>=1));
    if (i>j) swap(A[i], A[j]);
  }
  
  for (int i=2;i<=N;i<<=1){
  	CP wn = (CP){ cos((LD)2*M_PI/i), flag*sin((LD)2*M_PI/i) };
  	for (int j=0;j>1;
  solve(l,mid,e+1,d[e][0]);
  solve(mid+1,r,e+1,d[e][1]);
  if (e==0){
  	mid=(l+r)>>1;
  }
  int N , l0=mid-l+2, l1=r-mid+1;
  for (N=1;N<=l0+l1+1;N<<=1);
  for (int i=0;i

6、叢林前哨站

neerc原題,二分+半平面交,不多說

#include 
#include 
#include 

using namespace std;
const int Maxn=50005;
const double Eps=1e-9;
int Case,n,i,j,L,R,Mid,ans;
int q[Maxn],l,r;
struct Point
{
  double x,y;
  void read(){ scanf("%lf%lf",&x,&y); }
  Point operator +(const Point &a) const
    { return (Point){x+a.x, y+a.y}; }
  Point operator -(const Point &a) const
    { return (Point){x-a.x, y-a.y}; }
  Point operator *(const double &a) const
    { return (Point){x*a, y*a}; }
  Point operator /(const double &a) const
    { return (Point){x/a, y/a}; }
} dot[Maxn];
struct Seg { int s, t; } line[Maxn];

inline double mult(Point P1,Point P2)
 { return (P1.x*P2.y-P1.y*P2.x); }
inline double mult(Point P0,Point P1,Point P2)
 { return mult(P1-P0,P2-P0); }

inline Point cross(Seg l1,Seg l2){
  Point P0=dot[l1.s], P1=dot[l1.t];
  Point Q0=dot[l2.s], Q1=dot[l2.t];
  double u=mult(P0,P1,Q0), v=mult(P0,P1,Q1);
  Point ret = (Q1*u - Q0*v) / (u-v);
  return ret;
}

#define fabs(x) ((x)>0?(x):-(x))
inline bool out(Seg l0,Seg l1,Seg l2){
  Point p0=dot[l1.s]-dot[l1.t];
  Point p1=dot[l2.s]-dot[l2.t];
  if ( fabs( (p0.x*p1.y)-(p1.x*p0.y) ) < Eps ) return 1;
  Point DOT = cross(l1,l2);
  return mult(dot[l0.s],dot[l0.t],DOT)1);
}

int main(){
  freopen("jungle.in","r",stdin);
  freopen("jungle.out","w",stdout);
  scanf("%d",&Case);
  while (Case--){
  	scanf("%d",&n);
  	for (i=1;i<=n;i++)
  	  dot[n-i+1].read();
  	L=1; R=n-2;
  	ans = n-2;
  	while (L<=R){
  	  Mid=(L+R)>>1;
  	  if (Judge()) ans=Mid, R=Mid-1;
  	    else L=Mid+1;
  	}
  	printf("%d\n",ans);
  }
  return 0;
}

7、Circle

判斷n個圓交是否爲空。

跪跪跪跪跪跪。。。。。

本以爲把圓的交點搞出來,然後半平面交。。。各種寫跪!

陳老闆講了個很鬼畜的做法:先從x軸上找到交的區間[l,r],在區間裏找到每個圓的最高點和最低點,這些區間也應是有交的。如果這些區間交爲空,那麼可以判斷出這些圓在此處交爲空,否則繼續二分下去——實踐證明這居然過了。。。。orzorzorz

標程給了一個極角區間求教的東東,似乎也沒複雜度保證。。。。

#include 
#include  
#include 
#include 

using namespace std;
#define sqr(x) ( (x)*(x) )
const double Eps=1e-6;
struct Point{ double x,y; };
struct Seg{ int s, t; } line[20005];
struct Circle
{
  Point p;
  double r;
  void read(){ scanf("%lf%lf%lf",&p.x,&p.y,&r); }
} cir[20005];
double L,R;
int Case,n,i;

bool Judge(double L,double R){
  if (R-LR) {puts("No");continue;}
	if ( fabs(R-L)up) {puts("No"); continue;}
  	    else {puts("Yes"); continue;}
  	  
	}
	if ( Judge(L,R) ) puts("Yes");
	  else puts("No");
  }
  return 0;
}

8、Vector

好神的題目。。。。蒟蒻連暴力都不會打。。。。

觀察到對於所有和相等的幾何,一定是互不影響的。

不難發現最優方案一定是和相等的集合。(作爲民科我就不證明了。。。。)

不難發現x和sum-x的方案數是一樣的,這樣方案數就是對總和呈正態分佈。答案就是和爲sum/2的方案數,用遞推搞搞即可啦!

#include 
#include 
#include 

using namespace std;
const int Mod=(1e9)+7;
int n,m,i,j,a[2005];
int f[2005][2505];

int main(){
  freopen("vector.in","r",stdin);
  freopen("vector.out","w",stdout);
  scanf("%d",&n);
  for (i=1,m=0;i<=n;i++){
    scanf("%d",&a[i]);
    m += a[i];
  }
  for (i=0;i<=m/2;i++) f[0][i]=1;
  for (i=1;i<=n;i++)
  	for (j=0;j<=m/2;j++){
  	  if (j<=a[i]) f[i][j] = f[i-1][j];
  	    else f[i][j] = (f[i-1][j]-f[i-1][j-a[i]-1]+Mod)%Mod;
  	  if (j>0) f[i][j] = (f[i][j]+f[i][j-1])%Mod;
  	}
  printf("%d\n",(f[n][m/2]-f[n][m/2-1]+Mod)%Mod);
  return 0;
}

9、LMC的項鍊

又是burnside計數敲打

直接套用定理:所有置換下不動點的方案數的平均數。

要注意就是由於中間記錄的書有可能超過模數p,那麼需要將數x寫成x=a*p^b,其中a與p互質,這樣做逆元啥的比較方便。

#include 
#include 
#include 

using namespace std;
const int Mod=10007;
int ans,n,a,b,i;
struct arr
{
  int x, y;
  arr operator *(const int &a)const{
    arr ret = (*this);
    int aa = a;
    while (aa%Mod==0) aa/=Mod, ret.y++;
    ret.x = ret.x*aa%Mod;
    return ret;
  }
  arr operator *(const arr &a)const{
    arr ret;
    ret.x = x*a.x%Mod;
    ret.y = y+a.y;
    return ret;
  }
} jc[200005], ny[200005];

int gcd(int a,int b){
  while (b) b^=a^=b^=a%=b;
  return a;
}

int qck(int a,int b){
  int ret=1;
  for (;b>0;b>>=1){
    if (b&1) ret = ret*a%Mod;
    a = a*a%Mod;
  }
  return ret;
}

void init(){
  jc[0].x = 1;
  jc[0].y = 0;
  for (i=1;i<=n;i++)
    jc[i] = jc[i-1]*i;
  ny[0].x = 1;
  ny[0].y = 0;
  for (i=1;i<=n;i++){
    ny[i].x = qck(jc[i].x, Mod-2);
    ny[i].y = -jc[i].y;
  }
}

int C(int n, int m){
  if (m>n || m<0) return 0;
  arr ret = jc[n] * ny[m] * ny[n-m];
  if (ret.y!=0) return 0;
  return ret.x;
}

int main(){
  freopen("circle.in","r",stdin);
  freopen("circle.out","w",stdout);
  scanf("%d%d",&a,&b);
  n = a+b;
  init();
  for (i=1;i<=n;i++)
  if ( a%(n/gcd(i,n))==0 ){
    ans = ( ans + C( gcd(i,n), a/(n/gcd(i,n)) ) ) %Mod;
    //printf("rotate:%d %d\n",i,ans);
  }
  if (n&1){
    ans = ( ans + n*C( n/2, a/2 )%Mod ) %Mod;
  } else
  {
    if ((a&1)==0){
      ans = ( ans + n/2*C( n/2, a/2 )%Mod ) %Mod;
      ans = ( ans + n/2*C( n/2-1, a/2 )%Mod ) %Mod;
      ans = ( ans + n/2*C( n/2-1, a/2-1 )%Mod ) %Mod;
    } else
    {
      ans = ( ans + n*C( n/2-1, a/2 )%Mod ) %Mod;
    }
  }
  for (i=0;i

10、Byc的遊戲

歐拉路,注意判斷圖聯通即可

#include 
#include 
#include 

using namespace std;
char S[30005], T[30005];
int Case,n,i,d[50],fa[50],m1,m2;
bool v[50];

int gf(int x){
  int xx=x, xxx;
  while (xx!=fa[xx]) xx=fa[xx];
  while (x!=xx) xxx=x, x=fa[x], fa[xxx]=xx;
  return xx;
}

bool Judge(){
  for (int i=0;i<26;i++)
    if (d[i]!=0) return 0;
  int tmp;
  for (int i=0;i<26;i++)
    if (v[i]) {tmp = gf(i);break;}
  for (int i=0;i<26;i++)
    if (v[i] && tmp!=gf(i)) return 0;
  return 1;
}

int main(){
  freopen("game.in","r",stdin);
  freopen("game.out","w",stdout);
  scanf("%d",&Case);
  while (Case--){
    scanf("%d\n",&n);
    scanf("%s",S);
    scanf("%s",T);
    memset(d,0,sizeof(d));
    memset(v,0,sizeof(v));
    for (i=0;i<26;i++) fa[i]=i;
    for (i=0;i

11、Ccl的排列

貼題解啦,寫錯個東東調得吐血


#include 
#include 
#include 

using namespace std;
#define two(x) (1<<(x-1))
int n,a[105],i,j,k,cnt,s[105];
bool v[105];

struct BIGINT
{
  int h;
  int a[410];
  void init(int x)
  {
  	memset(a,0,sizeof(a));
  	h = 0;
  	while (x>0) a[h++]=x%10, x/=10;
  }
  
  bool operator >=(const BIGINT &x)const
  {
  	if (hx.h) return 1;
  	for (int i=h-1;i>=0;i--){
  	  if (a[i]x.a[i]) return 1;
    }
    return 1;
  }
  
  BIGINT operator +(const BIGINT &x)const
  {
  	BIGINT ret; ret.init(0);
  	int p = 0;
  	for (int i=0;i0) ret.a[ ret.h++ ] = p;
  	return ret;
  }
  BIGINT operator -(const BIGINT &x)const
  {
  	BIGINT ret; ret.init(0);
  	for (int i=0;i0 && ret.a[ret.h-1]==0) ret.h--;
  	return ret;
  }
  BIGINT operator *(const BIGINT &x)const
  {
  	BIGINT ret; ret.init(0);
  	if (h==0 || x.h==0) return ret;
  	for (int i=0;i0 && ret.a[ret.h-1]==0) ret.h--;
  	return ret;
  }
  BIGINT operator /(const BIGINT &x)const
  {
  	BIGINT ret; ret.init(0);
  	BIGINT p; p.init(0);
  	BIGINT w; w.init(10);
  	for (int i=h-1;i>=0;i--){
  	  p = p*w; p.a[0]=a[i];
  	  if (p.h==0) p.h++;
  	  while (p>=x) ret.a[i]++, p = p-x;
  	}
  	for (int i=h-1;i>=0;i--)
  	  if (ret.a[i]>0) {ret.h=i+1; break;}
  	return ret;
  }
  void print()
  {
  	if (h==0) {printf("0\n");return;}
  	for (int i=h-1;i>=0;i--)
  	  printf("%d",a[i]);
  	printf("\n");
  }
} g[105][105], f[105][105], jc[205], ans;

BIGINT C(int n,int m){
  BIGINT ret; ret.init(0);
  if (m>n || m<0) return ret;
  ret = jc[n]/jc[m]/jc[n-m];
  return ret;
}

int main(){
  freopen("per.in","r",stdin);
  freopen("per.out","w",stdout);
  scanf("%d",&n);
  for (i=1;i<=n;i++)
    scanf("%d",&a[i]);
  for (i=1,jc[0].init(1);i<=n*2;i++){
  	BIGINT tmp; tmp.init(i);
    jc[i] = jc[i-1]*tmp;
  }
  BIGINT tmp; tmp.init(2);
  for (i=1;i<=n;i++)
  if (!v[i]){
  	++cnt;
  	for (s[cnt]=0,k=i;!v[k];k=a[k])
  	  v[k]=1, s[cnt]+=2;
  	for (j=0;j<=s[cnt]/2;j++)
  	  g[cnt][j] = C(s[cnt]-j,j) + C(s[cnt]-j-1,j-1);
  }
  for (i=0;i<=cnt;i++) f[i][0].init(1);
  for (i=1;i<=cnt;i++)
  	for (j=1;j<=n;j++)
  	  for (k=0;k<=s[i]/2&&k<=j;k++)
  	    f[i][j] = f[i][j] + (f[i-1][j-k] * g[i][k]);
  for (i=0;i<=n;i+=2)
    ans = ans + (jc[n-i]*f[cnt][i]);
  for (i=1;i<=n;i+=2)
    ans = ans - (jc[n-i]*f[cnt][i]);
  ans . print();
  return 0;
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章