HDU6333 Problem B. Harvest of Apples

考场上看到这个题的时候,我记得这个式子好像是不能化简的= =,所以我就开始想能不能从c(m,0)+c(m,1)+...+c(m,m)轻松推出c(n,0)+c(n,1)+c(n,2)....+c(n,m),因为前者就是2^m,如果能O(1)从m扩大到n就行了,结果发现从

c(m,0)+c(m,1)=sum1          (1)式

推到

c(m+1,0)+c(m+1,1)+..c(m+1,m)=sum2     (2)式

的规律

c(m+1,1)-c(m,1)=c(m,0),c(m+1,2)-c(m,2)=c(m,1),

所以从(1)式推到(2)就是 sum2=sum1+sum1-c(m,n)

然后看到T=1e5,n,m=1e5,突然就想到莫队,因为n加减1就用上面的公式O(1)转移,m加减1就用+c(n,m+1)或者-c(n,m),用lucas+预处理也可以O(1)转移。

打了6场多校,我队第一次做出了非签到题,感觉我很多次发挥都是想到莫队= =,上次湘潭也是莫队+二分树状数组A了一道主席树的题。。。

#include<bits/stdc++.h>
#define X first
#define Y second
#define pb push_back
#define mk make_pair
#define rep(i,l,r) for(int i=l;i<=r;++i)
using namespace std;
typedef long long LL;
const int maxn=1e5+5;
const int MAXN = 100010;  
const int mod = 1e9 + 7;  

int T,sz;
struct node
{
	int m,n,ind;
}a[maxn];
LL sum;
LL ans[maxn];
LL inv[MAXN + 10], fac[MAXN + 10];

void init()    
{    
    inv[0] = fac[0] = inv[1] = fac[1] = 1;    
    for(int i = 1; i < MAXN; i++)    
    fac[i] = fac[i - 1] * i % mod;    
    for(int i = 2; i < MAXN; i++)    
    inv[i] = (mod - (mod / i)) * inv[mod % i] % mod;//lucas?????    
    for(int i = 1; i < MAXN; i++)    
    inv[i] = inv[i - 1] * inv[i] % mod;     
}  
inline LL C(int n, int m)//???? C n,m     
{    
    if(n<m)return 0; 
    return (fac[n] * inv[m] % mod) * inv[n - m] %mod;     
}    

inline bool cmp(const node &x,const node &y)
{
	if(x.m/sz==y.m/sz)
		return x.n<y.n;
	return x.m/sz<y.m/sz;
}

inline void prework()
{
    scanf("%d",&T);
    sz=sqrt(T);
	for(int i=1;i<=T;i++)
    	scanf("%d%d",&a[i].n,&a[i].m),a[i].ind=i;
	sort(a+1,a+1+T,cmp);
}

inline void mainwork()
{
	int l=1,r=1;
	sum=2;
	for(int i=1;i<=T;i++)
	{
		while(r<a[i].n)
		{
			r++;
			sum=(sum+(sum-C(r-1,l)+mod)%mod)%mod;
		}
		while(r>a[i].n)
		{
			sum=(1ll*((sum+C(r-1,l))%mod)*inv[2])%mod;
			r--;
		}
		while(l<a[i].m)
		{
			sum=(sum+C(r,l+1))%mod;
			l++;
		}
		while(l>a[i].m)
		{
			l--;
			sum=(sum-C(r,l+1)+mod)%mod;
		}
		ans[a[i].ind]=sum;
	}
}

inline void print()
{
	for(int i=1;i<=T;i++)
		printf("%lld\n",ans[i]);
}

int main()
{
    init();
    prework();
    mainwork();
    print();
    return 0;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值