【JZOJ100035】区间

Description

Input

Output

Sample Input

sample1:
4 2 10
5 1 1 10
sample2:
1000 97 96998351
41 1668 505 2333

Sample Output

sample1:
4
sample2:
1749769

Data Constraint

题解:

参考某dalao的代码
我们将这个长为n的序列分为几段长度为k的序列,若不能整分就单独处理多出来的一截
对于一个长度为k的小段,我们处理前缀积和后缀积,需要注意下标+1-1之类的 
处理出来有什么好处呢?我们O(2n)初始化后,后面求Tj就几乎是O(1)的了
实现方式是1到n-k+1跑一遍,若i % k等于1,就说明这一段T正好是一段我们刚才分出来的一段
这里就只需要一个前缀积或者后缀积
其他情况,就像Tj被一刀两断,前一段我们用一个后缀积,后一段我们用一个前缀积
然后就是直接用longlong数组要MLE,这个dalao用了一个神奇的乘1LL,貌似是强转longlong就过了= =
果然还是您太强啦,我太弱啦

代码:
 

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<string>
#include<cmath>
#include<cctype>
#include<cstdlib>
#include<climits>
#include<iomanip>
#include<stack>
#include<queue>
#include<vector>
#include<set>
#include<map>
#define MAXA 20000005
#define ipt(x) scanf("%d",&x)
using namespace std;
typedef long long LL;
int n,k,MOD,Ans,Blocknum,head,Pre[MAXA],Back[MAXA];
int A,B,C,D,S[MAXA];
int main() {
//	freopen("range.in","r",stdin);
//	freopen("range.out","w",stdout);
	scanf("%d %d %d",&n,&k,&MOD);
	scanf("%d %d %d %d",&A,&B,&C,&D);
	S[1] = A;
	for(int i=2;i<=n;i++)
	    S[i] = (S[i-1] * 1LL * B + C) % D;
	Blocknum = n / k;
	for(int j=0;j<Blocknum;j++) {
		head = j * k + 1;
		Pre[head] = S[head];
		for(int i=head+1;i<head+k;i++)
		    Pre[i] = Pre[i-1] * 1LL * S[i] % MOD;
		Back[head+k-1] = S[head+k-1];
		for(int i=head+k-2;i>=head;i--)
		    Back[i] = Back[i+1] * 1LL * S[i] % MOD;
	}
	if(n % k) {
		head = Blocknum * k + 1;
		Pre[head] = S[head];
		for(int i=head+1;i<=n;i++)
		    Pre[i] = Pre[i-1] * 1LL * S[i] % MOD;
		Back[n] = S[n];
		for(int i=n-1;i>=head;i--)
		    Back[i] = Back[i+1] * 1LL * S[i] % MOD;
	}
	for(int i=1;i<=n-k+1;i++) {
		if(i % k == 1)
		   Ans ^= Pre[i+k-1];
		else Ans ^= Back[i] * 1LL * Pre[i+k-1] % MOD;
	}
	printf("%d",Ans);
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值