题解:P2592 [ZJOI2008] 生日聚会
Nt_Tsumiki · · 题解
反射容斥好题啊。
提供一种理论复杂度
首先将本题转化到网格图上:
对于
对于坐一个女孩,我们可以看成
我们考虑怎么在网格图上刻画这个东西,我们不妨枚举两个边界
但是这样会算重,对于一条合法的路径它会被算
然后上面的格路计数部分可以使用反射容斥计算,需要算
PS:由于 exlucas 常数过大,实际上本题数据范围下跑不过
附两种计算组合数方法的提交记录:link1,link2
#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdio>
#include <cmath>
#define LL long long
#define MOD 12345678
#define N 10000005
inline int R() {
int x=0; bool f=0; char c=getchar();
while (!isdigit(c)) f|=(c=='-'),c=getchar();
while (isdigit(c)) x=x*10+c-'0',c=getchar();
return f?-x:x;
}
template<typename T>
void W(T x,int op=0) {
if (x<0) return putchar('-'),W(-x,op);
if (x>9) W(x/10); putchar(x%10+'0');
if (op) putchar(op==1?' ':'\n');
}
using namespace std;
int n,m,k;
namespace EXlucas {
LL quickpow(LL a,LL k,int P) {
LL res=1;
while (k) {
if (k&1) res=res*a%P;
a=a*a%P,k>>=1;
}
return res;
}
LL exgcd(LL a,LL b,LL &x,LL &y) {
if (!b) return x=1,y=0,a;
LL d=exgcd(b,a%b,x,y),tx=x;
x=y,y=tx-(a/b)*y;
return d;
}
LL mul(LL a,LL b,int P) {
a=(a%P+P)%P,b=(b%P+P)%P;
LL res=0;
while (b) {
if (b&1) res=(res+a)%P;
a=(a+a)%P,b>>=1;
}
return res;
}
LL excrt(int n,LL *r,LL *mod) {
LL R=r[1],P=mod[1];
for (int i=2;i<=n;i++) {
LL x,y,d=__gcd(P,mod[i]),tm=P/d*mod[i];
exgcd(P/d,mod[i]/d,x,y);
R=(R+mul((r[i]-R)/d,mul(x,P,tm),tm))%tm,P=tm;
}
return (R+P)%P;
}
LL f(int n,int p,int P) {
if (!n) return 1;
LL k=1,d=1;
for (int i=1;i<=P;i++)
if (i%p) k=k*i%P;
k=quickpow(k,n/P,P);
for (int i=P*(n/P);i<=n;i++)
if (i%p) d=d*(i%P)%P;
return f(n/p,p,P)*k%P*d%P;
}
LL g(int n,int p) {
if (n<p) return 0;
return n/p+g(n/p,p);
}
LL exlucas(int n,int m,int P) {
if (n<m or n<0 or m<0) return 0;
LL *r=new LL[2*(int)sqrt(P)],*c=new LL[2*(int)sqrt(P)];
int cnt=0;
for (int i=2;i*i<=P;i++)
if (P%i==0) {
int tmp=1,phi;
while (P%i==0) tmp*=i,P/=i;
phi=tmp/i*(i-1);
c[++cnt]=tmp;
r[cnt]=f(n,i,tmp)*quickpow(f(m,i,tmp),phi-1,tmp)%tmp
*quickpow(f(n-m,i,tmp),phi-1,tmp)%tmp
*quickpow(i,g(n,i)-g(m,i)-g(n-m,i),tmp)%tmp;
}
if (P>1) {
c[++cnt]=P;
r[cnt]=f(n,P,P)*quickpow(f(m,P,P),P-2,P)%P
*quickpow(f(n-m,P,P),P-2,P)%P
*quickpow(P,g(n,P)-g(m,P)-g(n-m,P),P)%P;
}
LL res=excrt(cnt,r,c);
delete[] r,c;
return res;
}
} using EXlucas::exlucas;
LL calc(int k) {
LL res=0;
for (int l=min(m-n,0)-1,r=min(m-n,0)+k+1;r>max(m-n,0);l--,r--)
for (int i=(n+r)/(r-l);n-i*(r-l)<=n+m;i--)
(res+=exlucas(n+m,n-i*(r-l),MOD)-exlucas(n+m,n-i*(r-l)+r,MOD))%=MOD;
return (res+MOD)%MOD;
}
int main() {
n=R(),m=R(),k=R();
if (k<abs(n-m)) return W(0,2),0;
if (k>=max(n,m)) return W(exlucas(n+m,n,MOD),2),0;
W((calc(k)-calc(k-1)+MOD)%MOD,2);
return 0;
}