2016多校集训---hdu5794

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 ;
    }
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值