Span

Span

[Description]

给出n个整数xiSi的计算规则如下:

 1

|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组数据

对于每组数据一行两个整数,分别为nm

[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; 
} 




  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值