Span
[Description]
给出n个整数xi,Si的计算规则如下:
|Ai|表示集合Ai的元素个数
例如,X = {40, 2, 10, 50, 30, 15},那么S = {1, 1, 2, 4, 1, 1}
Xi序列是第i个素数(第一个素数为2)对m取模后的值,现需要计算出Xi对应的Si的所有元素之和对m取模后的值
[Input]
第一行一个整数T,表示T组数据
对于每组数据一行两个整数,分别为n和m
[Output]
对于每组数据输出集合S中所有元素的和对m取模后的结果
[Sample Input]
3
7 10
10 16
10 7
[Sample Output]
0
5
6
[Hint]
1 <= n, m <= 100000
对于第一个样例: X=[2, 3, 5, 7, 1, 3, 7] S=[1, 2, 3, 4, 1, 2, 7]
答案为 (1+2+3+4+1+2+7) % 10 = 0.
/*
这道题首先要打一个100000个素数的表,需要用到O(2*N)的筛素数
O(N)的方法:
短小精悍的线性时间素数筛法
然后就类似以前做的题(吃早饭,或山峰)
这里给下大约的吃早饭题意
每个同学都面向窗口,一共有N个同学。现在XJ想知道每个同学能够看到的前面的同学的个数和是多少。
定义一个同学能够看到的人为在他前面且身高严格低于他的人,并且他的视线会被在他前面第一个身高大于等于他的人挡住。也就是说无论如何也无法看到再前面的人了。
这种题有两种做法:
①用栈来维护
②使用一个fa[ ]数组来保存
上代码了
#include<cstdio>
#include<iostream>
#include<cstring>
#include<stack>
using namespace std;
/*
吃早饭问题!!!
有两种方法:①用栈来维护②用fa数组来维护
╮(╯▽╰)╭哎!
两次写栈都挂了!!
*/
int flag[1500010];
int p[100010];//素数表
int a[100010];
int s[100010];
int lf[100010];
int cnt,t,n,m,sum;
stack<int>st;
void make_prime(int m) //筛素数O(2N)
{
for(int i=2;i<=m;i++)
{
if(!flag[i])p[cnt++]=i;
for(int j=0;j<cnt&&p[j]<=m/i;j++)
{
flag[i*p[j]]=1;
if(i%p[j]==0) break;
}
}
}
void finds_fa()
{
for(int i=1;i<=n;i++)
{
for(int j=i;j>=1;j--)
{
if(a[i]>=a[j])
{
if(s[j])
{
s[i]=s[i]+s[j];
j=lf[j];
lf[i]=j;
}
else
{
s[i]++;
lf[i]=j;
}
}
else break;
}
}
}
void finds_stack()
{
a[0]=m;
st.push(0);
for(int i=1;i<=n;i++)
{
while(a[i]>=a[st.top()]) st.pop();
s[i]=i-st.top();
st.push(i);
if(a[i]>a[i-1]&&s[i-1]+1>s[i])
s[i]=s[i-1]+1;
}
}
int main()
{
//freopen("C - Span_prime.txt","w",stdout);
make_prime(1300000);
/*
printf("%d\n",cnt-1);
for(int i=0;i<cnt;i++)
printf("%d ",p[i]);
*/
cin>>t;
while(t--)
{
memset(s,0,sizeof(s));
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
{
a[i]=p[i-1]%m;
//超时
/*
for(int j=i;j>=1;j--)
if(a[j]<=a[i]) s[i]++;
else break;
*/
}
//finds_fa();
finds_stack();
/*
for(int i=1;i<=n;i++)
printf("%d%%%d=%d----->%d\n",p[i-1],m,a[i],s[i]);
*/
sum=0;
for(int i=1;i<=n;i++)
sum=(sum%m+s[i]%m)%m;
printf("%d\n",sum);
}
return 0;
}