题目
https://cn.vjudge.net/problem/ZOJ-3940
题意
给你n个模数,和一个0-m范围,Q次询问,每次问范围内有多少数结果是给定的数
思路
区间取模,对x个区间取模,最多会产生x+1个区间,即x个0-(x-1)的区间合并为一个,和0-(
所有最后最多会有2*n个区间,
对于所有的查询x,查找有多少区间又端点大于等于x,即答案
代码
#include
using namespace std;
#define ll long long
const ll mod = 1e9+7;
struct node
{
int r,cnt;
bool operator < (const node &a) const
{
return r < a.r;
}
}a[500005];
int sum[500005];
int qw[500005];
int main()
{
int t;
scanf("%d",&t);
while(t--)
{
int n,m;
scanf("%d%d",&n,&m);
node u;
u.r = m,u.cnt = 1;
priority_queue q;
q.push(u);
for(int i = 1;i <= n;i++)
{
int x;
scanf("%d",&x);
while(q.top().r >= x)
{
u = q.top();
q.pop();
int cnt = u.cnt;
while(!q.empty()&&q.top().r == u.r)
{
cnt+=q.top().cnt;
q.pop();
}
node v;
v.r = x - 1;
int num = cnt*(u.r/x);
v.cnt = num;
q.push(v);
v.r = u.r % x;
v.cnt = cnt;
q.push(v);
}
}
int p = 0;
while(!q.empty())
{
a[p].r = q.top().r;
a[p++].cnt = q.top().cnt;
q.pop();
}
sort(a,a+p);
memset(sum,0,sizeof(sum));
for(int i =p-1;i >= 0;i--)
{
sum[i] = sum[i+1] + a[i].cnt;
qw[i] = a[i].r;
}
int Q;
scanf("%d",&Q);
ll ans = 0;
for(int k = 1;k <= Q;k++)
{
int x;
scanf("%d",&x);
int id = lower_bound(qw,qw+p,x) - qw;
ans += (ll)k*sum[id];
ans %= mod;
}
printf("%lld\n",ans);
}
return 0;
}