| ||||
Problem B. Harvest of ApplesTime Limit: 4000/2000 MS (Java/Others) Memory Limit: 262144/262144 K (Java/Others)Total Submission(s): 454 Accepted Submission(s): 149 Problem Description There are n apples on a tree, numbered from 1 to n.
Input The first line of the input contains an integer T (1≤T≤105) denoting the number of test cases.
Output For each test case, print an integer representing the number of ways modulo 109+7.
Sample Input 2 5 2 1000 500
Sample Output 16 924129523
| ||||
分析:开始想啦很久,没思路。然后队友突然说可以用离线,突然想到,然后推啦一下和的O(1)递推关系。
离线排个序看能不能快速求出,想到离散化m,感觉时间复杂度太大。然后突然想到可以分块,分200块,复杂度递推100*n.计算排序好的每个值,由于每个块大小是1000,可以通过O(500)的时间求出答案。时间复杂度O(500T+500n)。
昨天感觉能过就写啦,没多想,还有分块也不是我负责的方面,其实分块能达到最有效果。时间复杂度理论上能降低一半。
代码
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N=1e5;
const int ND=500;
const LL MOD=1e9+7;
const LL ny=500000004;
LL fac[N+10],inv[N+10],ans[N+10];
struct node
{
int x,y,ind;
bool operator<(const node& c)const
{
if(x==c.x)
return y<c.y;
return x<c.x;
}
}a[N+10];
struct nd
{
LL val,in;
}v[510];
LL pod(LL x,LL n,LL MOD)
{
LL ret=1;
while(n)
{
if(n&1)ret=ret*x%MOD;
x=x*x%MOD;
n>>=1;
}
return ret;
}
void init(int n)
{
fac[0]=fac[1]=1;
inv[0]=inv[1]=1;
for(int i=2;i<=n;i++)
fac[i]=fac[i-1]*i%MOD;
inv[n]=pod(fac[n],MOD-2,MOD);
for(int i=n;i>1;i--)
inv[i-1]=inv[i]*i%MOD;
}
LL c(int n,int m)
{
return fac[n]*inv[m]%MOD*inv[n-m]%MOD;
}
int main()
{
init(N);
int T;
scanf("%d",&T);
for(int i=1;i<=T;i++)scanf("%d%d",&a[i].x,&a[i].y),a[i].ind=i;
sort(a+1,a+T+1);
int x,y,ii,m=1,k;
for(int i=1;i<=N;i++)
{
k=0;
for(int j=0;j<i;j+=ND,k++)
{
if(j==0)
v[k].val=1;
else
{
v[k].val=(v[k].val*2+MOD-c(i-1,j))%MOD;
}
v[k].in=j;
}
v[k].val=pod(2ll,(LL)i,MOD);
v[k].in=i;
while(m<=T&&a[m].x==i)
{
ii=a[m].ind;
x=a[m].y/ND;
y=a[m].y%ND;
if(y<=ND/2)
{
ans[ii]=v[x].val;
for(int j=v[x].in+1;j<=a[m].y;j++)
ans[ii]=(ans[ii]+c(i,j))%MOD;
}
else
{
ans[ii]=v[x+1].val;
for(int j=a[m].y+1;j<=v[x+1].in;j++)
ans[ii]=(ans[ii]+MOD-c(i,j))%MOD;
}
m++;
}
}
for(int i=1;i<=T;i++)
{
printf("%lld\n",ans[i]);
}
}