1. 程式人生 > 實用技巧 >2017 Mid Central Regional G.Hopscotch (組合計數)

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