2017 Mid Central Regional G.Hopscotch (组合计数)

 

这道题有点意思,给出点(N,N),你在原点处向目标点走,每次只能向x和y两个方向走路,每次xy两个方向的步幅分别不能小于dx和dy,问走到终点的方案数,答案对1e9 + 7取模

这道题最直接的想法就是爆搜,但是看了眼数据,1e6,状态都开不下。然后就发现x和y的走路是独立的,所以可以分而治之,x和y分别处理,相乘即为到x,y的方案数,相乘即为源点到(x,y)的方案数。刚开始感觉像是个完全背包,但是自己写了个之后感觉算法假了,完全背包的统计不正确而且有遗漏和重复,还有不合法的状态也加了进来。然后自己在笔记本上手动列出了第二个样例,3-2-2,2-3-2,2-2-3,突然让我想起来了二项式分布,然后发现这tm不就是组合数的隔板法问题么,以dx和dy为最基本的步数,然后剩下的多余的距离往上放就行了,总距离做为投放的数量,然后隔板法公式就行了,这样就可以了。翻出lucas板子,试了试可以过样例了,之后被t到怀疑人生,快速乘都上了还是不行。后来去网上搜组合数快速算法,才知道其实N处理逆元就行了,小费马一次log(1e9 + 5)常数太大不t才怪,然后粘了个板子,终于过了。

后面还有一个概率dp,虽然有思路怎么搞了但是还是没能固定下来具体的算法,等会看

#include <bits/stdc++.h>
using namespace std;
#define limit (2000000 + 5)//防止溢出
#define INF 0x3f3f3f3f
#define inf 0x3f3f3f3f3f
#define lowbit(i) i&(-i)//一步两步
#define EPS 1e-6
#define FASTIO  ios::sync_with_stdio(false);cin.tie(0);
#define ff(a) printf("%d\n",a );
#define pi(a,b) pair<a,b>
#define rep(i, a, b) for(ll i = a; i <= b ; ++i)
#define per(i, a, b) for(ll i = b ; i >= a ; --i)
#define MOD 998244353
#define traverse(u) for(int i = head[u]; ~i ; i = edge[i].next)
#define FOPEN freopen("C:\\Users\\tiany\\CLionProjects\\acm_01\\data.txt", "rt", stdin)
#define FOUT freopen("C:\\Users\\tiany\\CLionProjects\\acm_01\\dabiao.txt", "wt", stdout)
#define debug(x) cout<<x<<endl
typedef long long ll;
typedef unsigned long long ull;
inline ll read(){
    ll sign = 1, x = 0;char s = getchar();
    while(s > '9' || s < '0' ){if(s == '-')sign = -1;s = getchar();}
    while(s >= '0' && s <= '9'){x = (x << 3) + (x << 1) + s - '0';s = getchar();}
    return x * sign;
}//快读
void write(ll x){
    if(x < 0) putchar('-'),x = -x;
    if(x / 10) write(x / 10);
    putchar(x % 10 + '0');
}
const ll mod = 1e9 + 7;
ll quickPow(ll base, ll expo){
    ll ans = 1;
    while (expo){
        if(expo & 1)(ans *= base) %= mod;
        expo >>= 1;
        base = (base * base) % mod;
        base %= mod;
    }
    return ans % mod;
}
ll fact[limit],inv[limit];
#define maxn limit
#define fac fact
ll init(){
    fact[0]=1;
    for (int i=1;i< limit ;i++)
        fac[i]=fac[i-1]*i%mod;
    inv[maxn-1] = quickPow(fac[maxn-1],mod-2);
    for (int i=maxn-2;i>=0;i--)
        inv[i]=inv[i+1]*(i+1)%mod;
    return 0;
}
ll c(ll n,ll m){
    if (n<m) return 0;
    return fac[n]*inv[m]%mod*inv[n-m]%mod;
}
ll n,dx,dy;
ll dp[limit],dp2[limit];
ll mul(ll a, ll b){
    ll ans = 0;
    a %= mod, b %= mod;
    while (b){
        if(b &1)(ans += a) %= mod;
        (a +=a) %= mod;
        b >>= 1;
    }
    return ans % mod;
}

int main() {
#ifdef LOCAL
    FOPEN;
#endif
    n = read(), dx = read(),dy = read();
    ll ans = 0;
    init();
    rep(i ,0 , n / dx){
        ll N = n - (dx - 1) * i - 1, K = i - 1;
        dp[i] = c(N, K);
    }
    rep(i,1,n / dy){
        ll N = n - (dy - 1) * i - 1, K = i - 1;
        dp2[i] = c(N, K);
    }
    rep(i,0 , min(n/dx, n /dy)){
        ans = (ans + mul(dp[i], dp2[i])) % mod;
    }
    write(ans);
    return 0;
}

 

posted @ 2020-08-28 14:20  tiany7  阅读(144)  评论(0编辑  收藏  举报