11.18补充模板
unordered_map
基本参数
template < class Key, // unordered_map::key_type
class T, // unordered_map::mapped_type
class Hash = hash<Key>, // unordered_map::hasher
class Pred = equal_to<Key>, // unordered_map::key_equal
class Alloc = allocator< pair<const Key,T> > // unordered_map::allocator_type
> class unordered_map;
预设初始大小
unordered_map<int,int>mp(10000);\\预设大小为1e4的umap
hash函数(防止卡hash)
const int p1 = 998244353, p2 = 1e9 + 7, p3 = 1e9 + 9;
struct hashh{
size_t operator()(const int& xx)const
{
return (xx % p1) * (xx % p2) % p3;
}
};
unordered_map<int, int, hashh> mp;
Lucas定理
\(\dbinom{m}{n} \%p =\dbinom{m/p}{n/p} \dbinom{m\%p}{n\%p} \%p (p为质数)\)
证明:
由二项式定理展开可得结论一:\((1+x)^p = C_p^0x^0 + C_p^1x^1 + C_p^2x^2+…C_p^px^p=1+x^p (mod\quad p)\)
设\(m=ap+c,n=bp+d\),则\((1+x)^n = (1+x)^{bp+d}=(1+x^p)^b (1+x)^d (mod \quad p)\)
此时\(\dbinom{m}{n}x^m= \dbinom{a}{b} x^{ap} * \dbinom{c}{d} x^c\)
且当c>d时显然有\(\dbinom{c}{d}=\dbinom{m}{n}=0\)
QED.
扩展Lucas定理
一个相对简单的情况
当p为非质数时,\(C_p^i(1 <= i <= p-1) \equiv 0(mod\ p)\)无法保证,p因子可能会和p进行约分。
譬如\(\dbinom{4}{6}\%6=3≠0\)
当p可以被分解为几个质数均为1的质数时可以对质数使用lucas定理,最后再用crt合并即可。
更一般的情况
根据唯一分解定理,得到\(p=\prod \limits p^{k_i}_i\)
考虑在\(\mod p^{k_i}_i\)意义下的lucas定理,最后结果仍可以用crt合并。
大致方法是在\(\mod p^{k_i}_i\)意义下快速求阶乘,再合并阶乘结果为组合数:
首先我们先提取出所有p的倍数,对于n,其阶乘内部有\(\lfloor\frac{n}{p}\rfloor\)个p的倍数,把他们全部提取出来,结果就是\(p^{\lfloor\frac{n}{p}\rfloor} * \lfloor\frac{n}{p}\rfloor!\),其中 \(\lfloor\frac{n}{p}\rfloor!\)可以递归计算。
对于不是p的倍数的,每个\(p^k\)成一个循环节,在每个循环节里面是直接把乘积算出来,最后再套上\(⌊\frac{n}{p^k}⌋\)的指数。最后会剩余几项,那些直接暴力乘起来就行。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=100;
const double esp=1e-8;
ll w[10];
ll n,m,P;
ll sum;
template<typename T>
inline void read(T &x){
x=0;T fl=1;char tmp=getchar();
while(tmp<'0'||tmp>'9')fl=tmp=='-'?-fl:fl,tmp=getchar();
while(tmp>='0'&&tmp<='9')x=(x<<1)+(x<<3)+tmp-'0',tmp=getchar();
x=x*fl;
}
ll mul(ll a,ll b,ll t){
ll res=a*b-(ll)((long double)a/t*b+esp)*t;
return (res%t+t)%t;
}
ll exgcd(ll a,ll b,ll &x,ll &y){
if(!b){
x=1,y=0;return a;
}
ll d=exgcd(b,a%b,y,x);
y-=a/b*x;
return d;
}
ll inv(ll a,ll b){
ll x,y;
exgcd(a,b,x,y);
return (x%b+b)%b;
}
ll crt(ll b,ll t){return mul(mul(b,inv(P/t,t),P),P/t,P);}
ll qpow(ll a,ll b,ll t){
ll P=1;
while(b){
if(b&1)P=mul(P,a,t);
a=mul(a,a,t),b>>=1;
}
return P;
}
ll fac(ll n,ll pi,ll pk){
if(!n) return 1;
ll res=1;
for(int i=2;i<=pk;i++)if(i%pi)res*=i,res%=pk;
res=qpow(res,n/pk,pk);
for(int i=2;i<=n%pk;i++)if(i%pi)res*=i,res%=pk;
return res*fac(n/pi,pi,pk)%pk;
}
ll C(ll n,ll m,ll pi,ll pk){
ll d=fac(n,pi,pk),d1=fac(m,pi,pk),d2=fac(n-m,pi,pk);
ll k=0;
for(ll i=n;i;i/=pi)k+=i/pi;
for(ll i=m;i;i/=pi)k-=i/pi;
for(ll i=n-m;i;i/=pi)k-=i/pi;
return mul(mul(d,inv(d1,pk),pk),mul(qpow(pi,k,pk),inv(d2,pk),pk),pk);
}
ll exlucas(ll n,ll m){
ll res=0,tmp=P,pk;
for(ll i=2;i*i<=tmp;i++){
pk=1;
while(!(tmp%i))tmp/=i,pk*=i;
res+=crt(C(n,m,i,pk),pk),res%=P;
}
if(tmp>1)
res+=crt(C(n,m,tmp,tmp),tmp),res%=P;
return res;
}
int main(){
cin>>P>>n>>m;
for(int i=1;i<=m;i++)
read(w[i]),sum+=w[i];
if(sum>n)
printf("Impossible\n");
else{
ll ans=1;
for(int i=1;i<=m;i++)
ans*=exlucas(n,w[i]),ans%=P,n-=w[i];
printf("%lld\n",ans);
}
return 0;
}
中国剩余定理crt
O(n)
#include<bits/stdc++.h>
#define ll long long
#define ull unsigned long long
#define pii pair<int,int>
using namespace std;
const double eps = 1e-10;
const double pi = acos(-1.0);
int n;
ll a[30],m[30],M = 1;
/*
算法步骤:
计算模数积,然后遍历每个方程,让答案累加a[i]*M/m[i]*inv(M/m[i],m[i]);
其中inv(a,b)表示a在modb意义下的逆元。
注意,中国剩余定理必须要满足模数两两互质。
*/
template<class T> T gcd(T a, T b){
return !b?a:gcd(b,a%b);
}
void exgcd(ll a, ll b, ll& x, ll& y){
if(!b){
x = 1, y = 0;
return;
}
exgcd(b,a%b,y,x);
y -= a/b*x;
}
ll inv(ll a, ll b){
ll x,y;
exgcd(a,b,x,y);
return (x%b+b)%b;
}
ll solve(){
ll ans = 0;
for(int i = 1; i <= n; i++){
ans = (ans + a[i]*M/m[i]*inv(M/m[i],m[i]))%M;
}
return (ans%M+M)%M;
}
int main()
{
scanf("%d",&n);
for(int i = 1; i <= n; i++){
scanf("%lld%lld",&m[i],&a[i]);
M *= m[i];
}
printf("%lld\n",solve());
return 0;
}
扩展中国剩余定理ex_crt
O(nlogn)
本质解同余方程组,转化为求n个同余方程
#include<bits/stdc++.h>
#define ll long long
#define ull unsigned long long
#define pii pair<int,int>
using namespace std;
const double eps = 1e-10;
const double pi = acos(-1.0);
const int maxn = 1e6 + 10;
int n;
inline ll mul(ll a,ll b,ll mod){//O(1)取模快速乘,不会爆long long
return (a*b-(ll)((long double)a/mod*b)*mod+mod)%mod;
}
ll exgcd(ll a, ll b, ll& x, ll& y){
if(!b){
x = 1, y = 0;
return a;
}
ll d = exgcd(b,a%b,y,x);
y -= a/b*x;
return d;
}
ll a[maxn],m[maxn];
ll solve(){
ll a1,m1;
m1=m[1],a1=a[1];
for(int i = 2; i <= n; i++){
ll a2,m2,k1,k2;
m2=m[i],a2=a[i];
ll d = exgcd(m1,m2,k1,k2);
if((a2-a1)%d) return -1;
else{
k1 = mul(k1,(a2-a1)/d,m2/d);//这个地方必须要用取模快速乘
a1 = a1+k1*m1;
m1 = abs(m1/d*m2);
}
}
return (a1%m1+m1)%m1;
}
int main(){
cin>>n;
for(int i=1;i<=n;i++)
scanf("%lld%lld",&m[i],&a[i]);
printf("%lld\n",solve());
return 0;
}
z函数(扩展kmp)
O(n)
#include <iostream>
#include <vector>
#include <queue>
#include <set>
#include <algorithm>
#include <cmath>
#include <cstring>
#include <numeric>
#include <stack>
#include <map>
#include <bitset>
using namespace std;
#define repeat(n) for(int ___ghuhd = (n); ___ghuhd; --___ghuhd)
#define loop(i, l, r) for(int i = (l); i <= (r); ++i)
#define rev_loop(i, r, l) for(int i = (r); i >= (l); --i)
template<typename T>
inline void MIN(T& a, T b) { a = min(a, b); }
template<typename T>
inline void MAX(T& a, T b) { a = max(a, b); }
int read(){
int x=0,f=1;char c=getchar();
for(;!isdigit(c);c=getchar()) c=='-'?f=-1:1;
for(;isdigit(c);c=getchar()) x=x*10+c-'0';
return x*f;
}
#define READ(...) int __VA_ARGS__; INIT_BY_READ(__VA_ARGS__)
void INIT_BY_READ(int& a) { a = read(); }
template<typename... Args>
void INIT_BY_READ(int& a, Args&... args) {
a = read(); INIT_BY_READ(args...);
}
using LL = long long;
using PA = pair<int, int>;
#define int long long
const int maxn=2e7+100;
int n,m;
char s[maxn],t[maxn];
int z[maxn];
int p[maxn];
signed main(){
cin>>(s)>>(t);
n=strlen(s);
m=strlen(t);
z[0]=m;
for(int i=1,l=0,r=0;i<m;i++){
if(i<=r&&z[i-l]<r-i+1){
z[i]=z[i-l];
}
else{
z[i]=max(0ll,r-i+1);
while(i+z[i]<m&&t[z[i]]==t[z[i]+i])z[i]++;
}
if(i+z[i]-1>r)l=i,r=i+z[i]-1;
}
while(s[p[0]]==t[p[0]])p[0]++;
for(int i=1,l=0,r=0;i<n;i++){
if(i<=r&&z[i-l]<r-i+1)
p[i]=z[i-l];
else{
p[i]=max(0ll,r-i+1);
while(i+p[i]<n&&p[i]<m&&t[p[i]]==s[p[i]+i])p[i]++;
}
if(i+p[i]-1>r)l=i,r=i+p[i]-1;
}
int ans=0;
for(int i=0;i<m;i++)
ans^=(z[i]+1)*(i+1);
cout<<ans<<endl;
ans=0;
for(int i=0;i<n;i++)
ans^=(p[i]+1)*(i+1);
cout<<ans<<endl;
return 0;
}

浙公网安备 33010602011771号