[CSP-S模拟测试]:sum(数学+莫队)

题目传送门(内部题63)


输入格式

第一行有一个整数$id$,表示测试点编号。
第一行有一个整数$q$,表示询问组数。
然后有$q$行,每行有两个整数$n_i,m_i$。


输出格式

一共有$q$行,每行一个整数表示每组询问的答案$S_{n_i,m_i}$对$10^9+7$取模的结果。


样例

样例输入:

1
5
1 1
2 1
3 2
4 3
5 5

样例输出:

2
3
7
15
32


数据范围与提示

对于所有数据,$1\leqslant q,n_i,m_i\leqslant 10^5$。


题解

考场上把$80$分部分分都水全了,愣是没想到莫队……

先来考虑所有询问的$n_i$相等应该怎么办,预处理即可,考虑$S_{n,m-1}$如何转移到$S_{n,m}$,无非就是加上$C_n^m$即可,不再赘述。

现在考虑所有询问的$m_i$相等应该怎么办,显然预处理没有那么简单,考虑$S_{n-1,m}$如何转移到$S_{n,m}$,既然组合数可以用杨辉三角推得,不妨画个杨辉三角。

为方便,我现在只画出杨辉三角中的其中两行为例

设$1$号点为$n-1$行的行首,$4$号点为$n$行的行首,利用杨辉三角的性质,编号为$4$的点等于编号为$1$的点,编号为$5$的点等于编号为$1$的点和编号为$2$的点的加和,编号为$6$的点等于编号为$2$的点和编号为$3$的点的加和。

还可以发现,在从$n-1$行向$n$行转移的时候除了$3$号点以外其它点都被加了$2$次,只有$3$号点只加了$1$次,那么我们可以得出$S_{n,m}=S_{n-1,m}*2-C_{n-1}^m$,同理$S_{n-1,m}=\frac{S_{n,m}+C_{n-1}^m}{2}$。

利用这个性质我们就可以解决这个子问题了。

得出了这些性质,我们可以考虑莫队算法,$m$相当于$l$,$n$相当于$r$,这道题就解决了。

时间复杂度:$\Theta(n\sqrt{n})$。

期望得分:$100$分。

实际得分:$100$分。


代码时刻

#include<bits/stdc++.h>
using namespace std;
struct rec{int n,m,id,pos;}e[100001];
const int mod=1000000007;
const int inx=500000004;
int q;
long long ans[100001];
long long jc[100001],inv[100001];
long long qpow(long long x,long long y)
{
	long long res=1;
	while(y)
	{
		if(y%2)res=res*x%mod;
		y>>=1;
		x=x*x%mod;
	}
	return res;
}
void pre_work()
{
	jc[0]=1;
	for(long long i=1;i<=100000;i++)
		jc[i]=jc[i-1]*i%mod;
	inv[100000]=qpow(jc[100000],mod-2);
	for(int i=100000;i;i--)
		inv[i-1]=inv[i]*i%mod;
}
long long get_C(long long x,long long y){return jc[x]*inv[y]%mod*inv[x-y]%mod;}
long long lucas(long long x,long long y)
{
	if(!y)return 1;
	return get_C(x%mod,y%mod)*lucas(x/mod,y/mod)%mod;
}
bool cmp(rec a,rec b){return (a.pos)^(b.pos)?a.m<b.m:(((a.pos)&1)?a.n<b.n:a.n>b.n);}
int main()
{
	pre_work();int mxn=0;
	scanf("%d%d",&q,&q);
	for(int i=1;i<=q;i++)
	{
		scanf("%d%d",&e[i].n,&e[i].m);
		mxn=max(mxn,e[i].n);e[i].id=i;
	}
	int t=sqrt(mxn);
	for(int i=1;i<=q;i++)e[i].pos=(e[i].m-1)/t+1;
	sort(e+1,e+q+1,cmp);
	int m=0,n=0;
	long long now=1;
	for(int i=1;i<=q;i++)
	{
		while(n<e[i].n)now=(now*2%mod-lucas(n++,m)+mod)%mod;
		while(m<e[i].m)now=(now+lucas(n,++m))%mod;
		while(m>e[i].m)now=(now-lucas(n,m--)+mod)%mod;
		while(n>e[i].n)now=(now+lucas(--n,m))*inx%mod;
		ans[e[i].id]=now;
	}
	for(int i=1;i<=q;i++)printf("%lld\n",ans[i]);
	return 0;
}


rp++

原文地址:https://www.cnblogs.com/wzc521/p/11636670.html

时间: 2024-11-09 09:10:04

[CSP-S模拟测试]:sum(数学+莫队)的相关文章

20181009noip HZ EZ两校联考sum(莫队,组合数学)

题面戳这里 思路: noip考莫队???!!! 考场上死活没往这方面想啊!!!数据分治忘写endl50pts滚粗了 这里每个询问都有n,m两个参数 我们可以把它看做常规莫队中的l和r 然后利用组合数的可递推性质就好了 相信改变m大家都会写,n呢? 看图: 我们发现,$S_n^m = S_{n-1}^m \times 2 - C_n^{m+1} + C_{n-1}^{m+1}$ (因为杨辉三角的性质) 所以n也可以递推 套个莫队就好了 代码: #include<iostream> #includ

http://www.codeforces.com/contest/703/problem/D D. Mishka and Interesting sum (莫队的TLE)

/*莫队算法的常数优化 实战演练 虽然是TLE代码*/ #include<bits/stdc++.h> using namespace std; const int maxn = 1000000 + 100; int block; struct query{ int l, r, id; bool operator < (const query &rhs)const{ return (l/block == rhs.l /block) ? r < rhs.r : l/block

csp-s模拟测试50(9.22)「施工(单调栈优化DP)」&#183;「蔬菜(二维莫队???)」&#183;「联盟(树上直径)」

改了两天,终于将T1,T3毒瘤题改完了... T1 施工(单调栈优化DP) 考场上只想到了n*hmaxn*hmaxn的DP,用线段树优化一下变成n*hmaxn*log但显然不是正解 正解是很**的单调栈 可以想象到最优情况一定是将两端高于中间的一段平原填成一段平的坑,不然如果坑内存在高度差那么我们即使只将一部分抬升也肯定没有用处,并且如果中间的坑已经高于了两端,再向上升也肯定不优,然后就中间的坑可以很很小,也可以很长,对于这个模型我们首先想到n^2*h的DP 设当前表示的f[i]表示当前到了i节

[CSP-S模拟测试]:ants(回滚莫队)

题目描述 然而贪玩的$dirty$又开始了他的第三个游戏. $dirty$抓来了$n$只蚂蚁,并且赋予每只蚂蚁不同的编号,编号从$1$到$n$.最开始,它们按某个顺序排成一列.现在$dirty$想要进行$m$场比赛,每场比赛给出$l$和$r$,表示选出从左向右数第$l$只至第$r$只蚂蚁.被选出的蚂蚁需要快速地按编号从小到大排序,之后这些蚂蚁中编号连续的蚂蚁将围成一个圈.每场比赛结束后,蚂蚁们还需要快速地回到最开始的位置. 按照蚂蚁的审美标准,围成的圈越大美观值就越大.于是$dirty$每次需要

[CSP-S模拟测试]:飘雪圣域(莫队)

题目描述 $IcePrincess\text{_}1968$和$IcePrince\text{_}1968$长大了,他们开始协助国王$IceKing\text{_}1968$管理国内事物. $IcePrincess\text{_}1968$和$IcePrince\text{_}1968$住在一个宁静悠远的王国:$IceKingdom$——飘雪圣域.飘雪圣域有$n$个城镇,编号$1,2,3...n$.有些城镇之间有道路,且满足任意两点之间有且仅有一条路径.飘雪圣域风景优美,但气候并不是太好.根据$

hdu 5381 The sum of gcd 莫队+预处理

The sum of gcd Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others) Problem Description You have an array A,the length of A is nLet f(l,r)=∑ri=l∑rj=igcd(ai,ai+1....aj) Input There are multiple test cases. The first line

HDU 5381 The sum of gcd 莫队暴力

链接 题解链接:http://www.cygmasot.com/index.php/2015/08/15/hdu_5381/ 题意: 给定n长的序列 下面n个数给出这个序列 m个询问 下面m行给出询问的区间. 对于一个询问,输出这个区间内的任意子段的gcd 和. 思路: 因为一个数的gcd只会不变或下降,下降一次至少减半,下降至多32次,所以处理出每个数连续相同的gcd的区间. 然后暴力跑莫队. #pragma comment(linker, "/STACK:1024000000,1024000

【10.22校内测试】【二分】【二分图】【很像莫队的乱搞/树状数组】

Solution 谁能想到这道题卡读入??还卡了70pts??? 二分+$n^2$check就行了 Code #include<bits/stdc++.h> using namespace std; int n, m; int sum[2005][2005]; void read(int &x) { x = 0; char ch = getchar(); while(ch > '9' || ch < '0') ch = getchar(); while(ch >= '

(预处理+莫队算法)HDU - 5381 The sum of gcd

题意: 一个长度为n的数列,m次查询L到R之间所有连续子序列的gcd之和. 分析: 很明显的莫队算法. 很明显发现了gcd是单调递减的,并且最多存在32个的性质. 想了很久,脑补了许多种方法来拉伸L和R,但是都有漏洞. 实际上,这道题还是比较复杂的.. 在思考的过程中,我没有充分利用gcd的递减性质. 这题其实这题有共通之处,至少在我的做法上是这样的. 可以发现,在R向右拉伸的过程中,增加的和只是从L到R+1中的每一个后缀的和. 向左则为减,L的移动同理. 那么我们只要提前预处理每个位置的前缀所