https://vjudge.net/problem/ZOJ-3940
题意:
告诉你 N , M , A 1 . . . A n N,M,A_1...A_n N,M,A1...An,每次询问 Y Y Y求 [ 0 , M ] [0,M] [0,M]有多少个 X X X满足: X % A 1 % A 2... % A n = Y X\%A1\%A2...\%An=Y X%A1%A2...%An=Y。
解析:
套路题, [ 0 , 20 ] % 20 → [ 0 , 19 ] , [ 0 , 0 ] [0,20]\%20 \to [0,19],[0,0] [0,20]%20→[0,19],[0,0],相当于每次取模让一个大区间变为两种小区间(第一种区间可能有多个)。
用 m a p map map记录下 [ 0 , R ] [0,R] [0,R]的个数 n u m num num。
每次模上 v a l val val时,在map里面把所有 R > = v a l R>=val R>=val的区间(lower_bound)操作一遍即可。
最后统计答案的时候对所有 Y Y Y排序,因为 R ≥ Y R\geq Y R≥Y的区间都会对 Y Y Y有贡献,所以统计也很简单。
时间复杂度保证:
显然,拆分后的两个区间对下一次拆分都有效的次数不会超过logm次(极限情况每次插成两种差不多大小的区间,长度/2)。
/*
* Author : Jk_Chen
* Date : 2020-08-15-12.41.37
*/
#include
using namespace std;
#define LL long long
#define LD long double
#define rep(i,a,b) for(int i=(int)(a);i<=(int)(b);i++)
#define per(i,a,b) for(int i=(int)(a);i>=(int)(b);i--)
#define mmm(a,b) memset(a,b,sizeof(a))
#define pb push_back
#define pill pair
#define fi first
#define se second
void test(){cerr<<"\n";}
template<typename T,typename... Args>void test(T x,Args... args){cerr<<"> "<<x<<" ";test(args...);}
const LL mod=1e9+7;
const int maxn=1e5+9;
const int inf=0x3f3f3f3f;
LL rd(){ LL ans=0; char last=' ',ch=getchar();
while(!(ch>='0' && ch<='9'))last=ch,ch=getchar();
while(ch>='0' && ch<='9')ans=ans*10+ch-'0',ch=getchar();
if(last=='-')ans=-ans; return ans;
}
#define rd rd()
/*_________________________________________________________begin*/
map<int,int>Count;
pill Q[maxn];
int main(){
int t=rd;
while(t--){
int n=rd,m=rd;
Count.clear();
Count[m]=1;///[0,m]
while(n--){
///拆分后的两个区间对下一次拆分都有效的次数不会超过logm次
/// [0,20]%20 -> [0,19] [0,0]
/// 19->1 20->1 38->1 39->2
/// [0,19]%20不变
int val=rd;
auto it=Count.lower_bound(val-1);
while(it!=Count.end()){
int R=(*it).first,num=(*it).second;
Count.erase(it++);
int b=(R+1)/val;
Count[val-1]=(1ll*Count[val-1]+(1ll*b*num)%mod)%mod;
if((R+1)%val){
Count[(R+1)%val-1]=(1ll*Count[(R+1)%val-1]+num)%mod;
}
}
}
int q=rd;
rep(i,1,q){
Q[i]={rd,i};
}
sort(Q+1,Q+1+q);
auto it=Count.end();
it--;
LL ans=0,sum=0;
bool End=0;
per(i,q,1){
while(!End){
int R=(*it).first,num=(*it).second;
if(R>=Q[i].fi){
sum=(sum+1ll*num)%mod;
if(it!=Count.begin()){
it--;
continue;
}
else{
End=1;
break;
}
}
else break;
}
ans=(ans+sum*Q[i].se)%mod;
}
printf("%lld\n",ans);
}
return 0;
}
/*_________________________________________________________end*/