題意:乙個人有n個女朋友,每個女朋友都有乙個班級a[i],現有m個詢問。每個詢問有乙個區間範圍[l,r],表示這個人想要約[l,r]範圍內的女生有幾種約法。(第l個女生到第r個女生的區間,而不是班級).
分析:
給出公式,對於範圍[l,r]來說可能的情況為(r-l+1)!/【(num[x1]!)(num[x2]!)……(num[xn]!)】 ,x1,x2,……,xn為[l,r]區間內出現過的所有不相同的數,num表示該數出現的次數
即情況數=該區間範圍內所有數的全排列/每個數各自的全排列的求和。
因為出現取餘操作,所以當出現除法操作時需要用到逆元(又因為mod=1e9+7為乙個質數,所以考慮用費馬小定理)
因為有很多階乘操作,所以通過預處理得到可能範圍內所以數的階乘(儲存在d[i]中)和階乘的逆元(儲存在nd[i]中)
因為答案的分子(即(r-l+1)!可在預處理後直接訪問得到),所以在中間訪問過程中只記錄分母(記作sum)
當num[a[p]]]++時,需要sum*=num[a[p]];當num[a[p]]–時,需要sum/=num[a[p]];
ac**:
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
#define ll long long
const int maxn =30000+10;
const ll mod =1000000007;
ll a[maxn],num[maxn],sum,ans[maxn];
ll fac[maxn]=,f[maxn]=;
ll len;
void init()
} ll quick(ll x,ll y)
return sum%mod;
}struct query
q[maxn];
bool cmp(query a, query b)
else
}int main()
sort(q+1,q+m+1,cmp);
int l=1,r=1;
num[a[1]]=1;
sum=1;
for(int i=1; i<=m; i++)
while(l>q[i].l)
while(lwhile(r>q[i].r)
ans[q[i].id]=fac[r-l+1]*quick(sum,mod-2)%mod;
}for(int i=1; i<=m; i++)
printf("%lld\n",ans[i]);
}return
0;}
HDU 5145 分塊 莫隊
給定n個數,q個詢問 l,r 區間,每次詢問該區間的全排列多少種。數值都是30000規模 首先考慮計算全排列,由於有同種元素存在,相當於每次在len r l 1長度的空格隨意放入某種元素即 binom 那麼下種元素即為 binom 以此類推,直至最後直接填滿,那麼全排列為 然後可以發現可以直接o 1...
YbtOJ 序列計數 組合數學,莫隊
求有多少個長度在 l,r 之間,值域是 1,n 的嚴格上公升子串行 1 leq t,n leq 10 5,1 leq l leq r leq 10 5 先轉換成兩個字首和的差,那麼相當於我們要快速求 sum m binom 的值。考慮到我們有組合數恒等式 binom n m binom binom ...
HDU6333 莫隊演算法
給你n,m求 i 0mcn i 1 09 7 sum m 10 9 7 i 0m cni 10 9 7 t組資料t 1 05,1 m,n 105 t leq 10 5,1 leq m,n leq 10 5 t 105,1 m,n 10 5。這題常規思路暴力求字首和時間複雜度和空間複雜度都是顯然不夠的...