1. 程式人生 > >BZOJ1129: [POI2008]Per

BZOJ1129: [POI2008]Per

hide main Go ++ names 數列 合並 所有 ret

比賽題。懶得寫crt而丟暴力。

問$n \leq 300000$的數列的字典序,$mod \ \ m$,不保證$m$是質數,數列$\leq 300000$,有重復。

雖然說這種強行套兩個知識的題目很令人厭惡,但征服他們才是我們厭惡的資本

首先$p_i$表示數列第$i$個數,$c_i$表示值為$i$有多少個,$t$表示所有數字的最大值,我們要求的是$1+\sum_{i=1}^{n} \sum_{j=1}^{p_i-1} \frac{(n-i)!}{(c_j-1) \prod_{k=1}^{t}[k \neq j]c_k}$。

上下同乘$c_j$,得,等會!!!!!嚴肅註意,在這裏同乘$c_j$,若$c_j=0$則會出現奇怪錯誤!!所以在式子轉化的過程中千萬記得,把條件寫上去。在這卡了1.5h。

$\sum_{i=1}^{n} \frac{(n-i)!}{\prod_{k=1}^{t}c_k}\sum_{j=1}^{p_i-1}c_j(這坨東西不為0)$.

好的!由於$c$會變,後面那坨用樹狀數組解決,而那個分式需要對$m$取$mod$,不方便,就把$m$分解完,$m=\sum_{i=1}^{k}a_i^{b_i}$,枚舉每個$a_i^{b_i}$做膜數,用歐拉定理求逆元,把質因子$a_i$計指數單獨拿出來算。最後用中國剩余定理合並。

技術分享圖片
  1 //#include<iostream>
  2 #include<cstring>
  3 #include<cstdlib>
  4
#include<cstdio> 5 //#include<time.h> 6 //#include<complex> 7 #include<algorithm> 8 #include<stdlib.h> 9 using namespace std; 10 11 int n,mod; 12 #define maxn 300011 13 int cnt[maxn],pp[maxn],a[maxn]; 14 struct BIT 15 { 16 int a[maxn],n; 17 void clear(int
m) {n=m;} 18 void add(int x,int v) {for (;x<=n;x+=x&-x) a[x]+=v;} 19 int query(int x) {int ans=0; for (;x;x-=x&-x) ans+=a[x]; return ans;} 20 }t; 21 22 int powmod(int a,int b,int mod) 23 { 24 int ans=1; 25 while (b) 26 { 27 if (b&1) ans=1ll*ans*a%mod; 28 a=1ll*a*a%mod; b>>=1; 29 } 30 return ans; 31 } 32 33 int mm[maxn],ci[maxn],phi[maxn],mi[maxn],num[maxn],ln; 34 void dec() 35 { 36 int tmp=mod; ln=0; 37 for (int i=2;1ll*i*i<=tmp;i++) if (tmp%i==0) 38 { 39 num[++ln]=i; mi[ln]=1; 40 while (tmp%i==0) tmp/=i,mi[ln]*=i; 41 } 42 if (tmp>1) num[++ln]=tmp,mi[ln]=tmp; 43 for (int i=1;i<=ln;i++) phi[i]=mi[i]-mi[i]/num[i]; 44 } 45 46 int xx[maxn]; 47 int china() 48 { 49 int ans=0; 50 for (int i=1;i<=ln;i++) 51 { 52 int w=mod/mi[i],ni=powmod(w,phi[i]-1,mi[i]); 53 ans=(ans+1ll*w*ni%mod*xx[i])%mod; 54 } 55 return ans; 56 } 57 58 int main() 59 { 60 scanf("%d%d",&n,&mod); int Max=0; 61 for (int i=1;i<=n;i++) scanf("%d",&a[i]),cnt[a[i]]++,Max=max(Max,a[i]); 62 t.clear(Max); 63 dec(); 64 for (int j=1;j<=ln;j++) 65 { 66 mm[j]=1; 67 for (int tmp=1;1ll*tmp*num[j]<=n;tmp*=num[j]) ci[j]+=n/(tmp*num[j]); 68 for (int i=1;i<=n;i++) 69 { 70 int tmp=i; while (tmp%num[j]==0) tmp/=num[j]; 71 mm[j]=1ll*mm[j]*tmp%mi[j]; 72 } 73 for (int i=1;i<=Max;i++) 74 { 75 for (int k=1;1ll*k*num[j]<=cnt[i];k*=num[j]) ci[j]-=cnt[i]/(k*num[j]); 76 for (int k=1;k<=cnt[i];k++) 77 { 78 int tmp=k; while (tmp%num[j]==0) tmp/=num[j]; 79 mm[j]=1ll*mm[j]*powmod(tmp,phi[j]-1,mi[j])%mi[j]; 80 } 81 } 82 } 83 for (int i=1;i<=Max;i++) if (cnt[i]) t.add(i,cnt[i]); 84 for (int i=1;i<=n;i++) 85 { 86 int nowt=t.query(a[i]-1); 87 for (int j=1;j<=ln;j++) 88 { 89 int tmp=n-i+1; 90 while (tmp%num[j]==0) ci[j]--,tmp/=num[j]; 91 mm[j]=1ll*mm[j]*powmod(tmp,phi[j]-1,mi[j])%mi[j]; 92 if (nowt) xx[j]=(xx[j]+mm[j]*1ll*powmod(num[j],ci[j],mi[j])%mi[j]*nowt)%mi[j]; 93 tmp=cnt[a[i]]; 94 while (tmp%num[j]==0) ci[j]++,tmp/=num[j]; 95 mm[j]=1ll*mm[j]*tmp%mi[j]; 96 } 97 cnt[a[i]]--; t.add(a[i],-1); 98 } 99 printf("%d\n",(china()+1)%mod); 100 return 0; 101 }
View Code

BZOJ1129: [POI2008]Per