Lucas + dp
注意一个点:
如果是容斥肯定超时,但是容斥原理有一点,那就是无序性、、、比如2的倍数包含了3的倍数。3的倍数包含了2的倍数。所以用2^n来实现、、
而如果C = A ^ B , 且a 属于 A 也可能 属于B 。 但是 a属于B 就一定不会 属于A , 那就可以使用DP , 来加速容斥。。。。n^2 复杂度 。。贼强/。。。
比如此题:
dp[i] 表示 第一个经过的障碍是i的正好到达i障碍处的种类数。。
按照顺序排序。排在前面的障碍如果经过 ,可能会经过后面的。但是如果排在后面的第一次经过,就一定不会经过前面的,所以就可以有转移方程
dp[i] = tot(i) - dp[j] * tot(j->i) (j < i) ;
而tot 表示 不考虑障碍数,的种类数。也就是一个简单的组合问题。,有公式的。使用lucas定理来求大数的组合数。但是mod必须是素数,并且是100000左右。。
就可以球出来了。。。DP,套路。。。可以使用DP解决有顺序容斥题。。。
#include <map>
#include <set>
#include <stack>
#include <queue>
#include <cmath>
#include <string>
#include <vector>
#include <map>
#include <set>
#include <stack>
#include <queue>
#include <cmath>
#include <string>
#include <vector>
#include <cstdio>
#include <cctype>
#include <cstring>
#include <sstream>
#include <cstdlib>
#include <iostream>
#include <algorithm>
#pragma comment(linker,"/STACK:102400000,102400000")
using namespace std;
#define MAX 1000005
#define MAXN 2000005
#define maxnode 500010
#define sigma_size 30
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define lrt rt<<1
#define rrt rt<<1|1
#define mid int m=(r+l)>>1
#define LL long long
#define ull unsigned long long
#define mem0(x) memset(x,0,sizeof(x))
#define mem1(x) memset(x,-1,sizeof(x))
#define meminf(x) memset(x,INF,sizeof(x))
#define lowbit(x) (x&-x)
#define S(n) scanf("%d",&n)
#define P(n) printf("%d ",n)
#define PN(n) printf("%d\n",n)
#define FP(k) freopen(k , "r" ,stdin)
#define RPTI(s , n) for(int i=s;i<n;i++)
#define RPTJ(s , n) for(int j=s;j<n;j++)
#define RPTK(s , n) for(int k=s;k<n;k++)
#define RPTL(s , n) for(int l=s;l<n;l++)
const LL mod = 1000000;
///const int prime = 999983;
const int INF = 0x3f3f3f3f;
const int INFF = 1e9;
const double pi = 3.141592653589793;
const double inf = 1e18;
const double eps = 1e-10;
inline int read_int(){
int ret=0;
char tmp;
while(!isdigit(tmp=getchar()));
do{
ret=(ret<<3)+(ret<<1)+tmp-'0';
}
while(isdigit(tmp=getchar()));
return ret;
}
/*******************************************/
typedef long long ll ;
const int moddd = 110119 ;
LL fact[moddd+100];
void Getfact(LL p){
fact[0]=1;
for(int i=1;i<p;i++){
fact[i]=(fact[i-1]*i)%p;
}
}
LL qpow(LL a,LL n,LL p){
LL ans=1;
while(n){
if(n&1) ans=ans*a%p;
a=a*a%p;
n>>=1;
}
return ans;
}
LL Lucas(LL n,LL m,LL p){
LL ans=1;
while(n&&m){
LL a=n%p,b=m%p;
if(a<b) return 0;
ans=(ans*fact[a]*qpow(fact[b]*fact[(a-b)]%p,p-2,p))%p;
n/=p;
m/=p;
}
return ans;
}
int cal(ll a , ll b){
if((2*b-a)%3!=0||2*b<a) return 0;
LL x2=(2*b-a)/3;
LL x1=b-2*x2;
if(x1<0) return 0;
return Lucas(x1+x2,x1,moddd);
}
struct node{
ll x, y ;
bool operator < (const node & n)const {
return x < n.x ;
}
}obs[200];
ll d[200] ;
int main(){
Getfact(moddd) ;
ll n,m,r;
int ca =0 ;
while(cin>>n>>m>>r){
printf("Case #%d: " , ++ca) ;
for(int i=0;i<r;i++) {
ll ta , tb ; cin>>ta>>tb;
obs[i].x = ta ; obs[i].y = tb ;
}
sort(obs , obs + r) ;
if(obs[r-1].x==n && obs[r-1].y==m) {
printf("0\n") ; continue ;
}
obs[r].x = n ; obs[r].y = m ;
for(int i=0;i<=r;i++){
d[i] = cal(obs[i].x-1 , obs[i].y-1) ;
for(int j=0;j<i;j++){
ll tx = obs[i].x-obs[j].x ;
ll ty = obs[i].y-obs[j].y ;
if(tx >= 0 && ty >= 0)
d[i]=d[i]+moddd-(d[j]*cal(tx , ty))%moddd;
d[i]%=moddd ;
}
}
cout << d[r] << endl ;
}
}