hdu5187 zhx's contest (組合數學+快速冪)
阿新 • • 發佈:2019-01-12
題意
給你一個n,一個p,
若1-n的單峰序列有ans個,
即先增後減或先減後增的序列均滿足要求,
求ans%p
思路來源
https://blog.csdn.net/qq_40379678/article/details/79149727
題解
有些博主的題解真是清晰易懂,十分感謝
自己還是太辣雞了,一遇組合數學就懵逼
考慮1,2,3,…,n的單增序列,
顯然,中間那個單峰只能是n,
那麼把左邊(n-1)個數取1個放在右邊,就是
…
取(n-1)個放在右邊,就是
先單增後單減序列ans=
反過來,先單減後單增序列ans=
這樣最後sum就是
特判n=1,sum是1,p=1時sum%p==0,其餘sum%p==1
注意n、p均1e18,相乘爆ll,所以要用快速乘,是為記
程式碼
#include <iostream> #include <cstdio> #include <cstring> #include <map> using namespace std; typedef long long ll; ll mul(ll x,ll n,ll mod) { ll res=0; while(n) { if(n&1)res=(res+x); if(res>=mod)res%=mod; x=x+x; if(x>=mod)x%=mod; n/=2; } return res; } ll modpow(ll x,ll n,ll mod) { ll res=1; while(n) { if(n&1)res=mul(res,x,mod); if(res>=mod)res%=mod; x=mul(x,x,mod); if(x>=mod)x%=mod; n/=2; } return res; } ll n,p; ll solve(ll n,ll p) { if(n==1) { if(p==1)return 0; else return 1; } else { ll res=1; res=modpow(2,n,p)-2; return (res+p)%p; } } int main() { while(~scanf("%lld%lld",&n,&p)) { printf("%lld\n",solve(n,p)); } return 0; }