hdu 6333 Problem B. Harvest of Apples 莫隊+組合數
Problem B. Harvest of Apples
Time Limit: 4000/2000 MS (Java/Others) Memory Limit: 262144/262144 K (Java/Others)
Total Submission(s): 2712 Accepted Submission(s): 1062
Problem Description
There are n apples on a tree, numbered from 1 to n.
Count the number of ways to pick at most
Input
The first line of the input contains an integer T (1≤T≤105) denoting the number of test cases.
Each test case consists of one line with two integers n,m (1≤m≤n≤105).
Output
For each test case, print an integer representing the number of ways modulo 109+7.
Sample Inpu
2
5 2
1000 500
Sample Output
16
924129523
Source
2018 Multi-University Training Contest 4
題意:就是求t次
思路:先打表然後暴力的話是每次基本上是每次O(n)的複雜度,然後t次就是O(n*n)的複雜度,如果把C(n,m)拆成兩半的話複雜度為O(n*n/2),這只是一個小小優化還是會T,正式比賽的時候是想到莫隊的但是沒想到怎麼救過組合數求和轉移的方式,當時頭抽了,沒有仔細去思考,去看楊輝三角,認真的思考的話這題也是可以過的,主要就是用楊輝三角推公式,然後莫隊減少複雜度
公式就是
(感謝群裡的那個奆佬)
注意:以前還不知道mod加const會比不用快,這題莫隊加const1800+ms,不加居然T了。這題對n和m的轉移還有先後順序,不然也會WA,應該是n>=m的問題吧;
程式碼:
#include<stdio.h>
#include<string.h>
#include<cmath>
#include<stdlib.h>
#include<time.h>
#include<algorithm>
#include<iostream>
#include<vector>
#include<queue>
#include<set>
#include<map>
#define ll long long
#define qq printf("QAQ\n");
using namespace std;
const int maxn=1e5+5;
const int inf=0x3f3f3f3f;
const ll linf=8e18+9e17;
const ll mod=1e9+7;
const double e=exp(1.0);
const double pi=acos(-1);
int block[maxn];
struct node{
int a,b,id;
}a[maxn];
bool cmp1(node a,node b)
{
if(block[a.a]!=block[b.a])return block[a.a]<block[b.a];
return block[a.b]<block[b.b];
//if(a.a!=b.a)return a.a<b.a;
//return a.b<b.b; 不分塊也是要T的
}
ll fac[maxn],inv[maxn],ans[maxn];
ll quick_pow(ll a,int n)
{
ll ans=1;
while(n)
{
if(n&1)ans=(ans*a)%mod;
n/=2;
a=(a*a)%mod;
}
return ans;
}
ll C(int n,int m)
{
return (((fac[n]*inv[n-m])%mod)*inv[m])%mod;
}
int main()
{
int n,m,t;
fac[0]=inv[0]=1;
for(int i=1;i<=100000;i++)
{
fac[i]=(fac[i-1]*i)%mod;
inv[i]=quick_pow(fac[i],mod-2);
}
scanf("%d",&t);
int tt=sqrt(maxn);
for(int i=1;i<=t;i++)
scanf("%d%d",&a[i].a,&a[i].b),a[i].id=i,block[i]=(i-1)/tt;
sort(a+1,a+t+1,cmp1);
int nown=1,nowm=1;
ll ans1=2;
for(int i=1;i<=t;i++)
{
while(a[i].b<nowm)//m先減少 m最後在增加 避免n<m導致出錯
{
ans1=((ans1-C(nown,nowm))%mod+mod)%mod;
nowm--;
}
while(a[i].a>nown){
ans1=((2*ans1%mod-C(nown,nowm))%mod+mod)%mod;
nown++;
}
while(a[i].a<nown)
{
nown--;
ans1=(((ans1+C(nown,nowm))%mod)*quick_pow(2,mod-2))%mod;
}
while(a[i].b>nowm)
{
nowm++;
ans1=(ans1+C(nown,nowm))%mod;
}
ans[a[i].id]=ans1;
}
for(int i=1;i<=t;i++)
printf("%lld\n",ans[i]);
return 0;
}