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; }
天才选手zerol的主页:https://zerol.me/
|
WeepingDemon的个人主页:https://weepingdemon.gitee.io/blog/