【CF1599F】 Mars 题解
ChuYilin2011 · · 题解
CF1599F 题解
前言
P3792 与这道题很类似,感兴趣的可以去做一做。
本人题解大多数通俗易懂,主要供蒟蒻食用,dalao 们不喜勿喷哦~ (其实我也是蒟蒻)
声明:数列哈希这条思路不是我本人想出来的,是上课的老师教我的。(就我这蒟蒻,这道题能想到哈希?)
题目大意
有一个序列
解题方法
必备知识
哈希,快速幂,组合数等。第一个最重要,后面两个主要用来优化。
分析
首先,给定这个区间,我们可以求出区间和
那么,这个区间“应有的样子”也就知道了。只需判断这个区间“是否是应有的样子”即可。考虑用哈希。
显然,我们要设计的哈希函数
首先想到的当然是直接累加,即
但是这样容易冲突。考虑取每个元素的
这样,问题就解决了,并且还有
所以,我们可以用类似前缀和的方式,求出每个区间实际的哈希值。但还有一个难点在于,如果每次询问都暴力算一遍该区间“应有的样子”的哈希值,那时间复杂度最坏
考虑等差数列
二项式展开得
整理得
交换
不难发现,此时,只要预处理组合数
所以,设
特别地,
那么序列
对应的哈希值应该是
时间复杂度:
预处理
预处理组合数:
单次询问:
总时间复杂度:其实也没必要。
代码
最终的时间复杂度,就取决于
#include <bits/stdc++.h>
using namespace std;
const int mod=1e9+7;
const int N=2e5+5;
int qpow(int x,int y){
int res=1;
while(y){
if(y&1) res=1ll*res*x%mod;
y>>=1;
x=1ll*x*x%mod;
}
return res;
}
const int K=37;
int C[K+5];//C[i] 表示 C(K,i)
int n,Q,s[N];
int ss[N],c[K+5][N];
int main(){
scanf("%d%d", &n, &Q);
for(int i=1;i<=n;i++){
scanf("%d",&s[i]);
s[i]=(s[i]+114514)%mod;//防卡技巧之同时加个东西,不影响结果
}
c[0][0]=1;
for(int i=1;i<=n;i++){
int tmp=1;
for(int j=0;j<=K;j++,tmp=1ll*tmp*i%mod)
c[j][i]=(c[j][i-1]+tmp)%mod;
ss[i]=(ss[i-1]+qpow(s[i],K))%mod;//“前缀哈希和”处理
s[i]=(s[i]+s[i-1])%mod;//前缀和处理
}
C[0]=1;
for(int i=1;i<=K;i++)
C[i]=C[i-1]*1ll*(K-i+1)%mod*qpow(i,mod-2)%mod;
while(Q--){
int x,y,d;
scanf("%d%d%d",&x,&y,&d);
int len=y-x+1,sum=(s[y]-s[x-1]+mod)%mod;
int st=1ll*(sum-1ll*len*(len-1)/2%mod*d%mod+mod)%mod*qpow(len,mod-2)%mod;
int res=0;
for(int i=0;i<=K;i++)
res=(res+1ll*C[i]*qpow(st,i)%mod*qpow(d,K-i)%mod*c[K-i][len-1]%mod)%mod;
if(res==(ss[y]-ss[x-1]+mod)%mod) printf("Yes\n");
else printf("No\n");
}
return 0;
}
经作者亲身试验,可放心食用。