【51nod 1589】移数博弈

题目大意

A A A 和小 B B B 在玩一个游戏。 他们拥有一个数列。小 A A A 在该数列中选择出最大的那个数,然后移出该数列;小 B B B 在剩下的数列中选择出最大的那个数,并乘上小 A A A 的那个值,作为他的答案。

那么现在问题来了。他们现在想换一种玩法,把该数列长度大于等于 2 2 2 的区间(即 n × ( n − 1 ) / 2 n\times (n-1)/2 n×(n1)/2 个区间)单独作为一个数列拿出来,然后做一次上述的游戏,然后计算出小 B B B 所有的答案,考虑到输出那么多数比较困难,因此他们想知道所有答案和对 1000000007 ( 1 0 9 + 7 ) 1000000007(10^9+7) 1000000007(109+7) 取模后的值。

样例解释: 该数列为 2 2 2 0 0 0 1 1 1 2 2 2 对于 1 − 2 1-2 12 的区间答案为 0 0 0 ,对于 1 − 3 1-3 13 的区间答案为 2 2 2 ,对于 1 − 4 1-4 14 的区间答案为 4 4 4 ,对于 2 − 3 2-3 23 的区间答案为 0 0 0 ,对于 2 − 4 2-4 24 的区间答案为 2 2 2 ,对于 3 − 4 3-4 34 的区间答案为 2 2 2

输入格式

第一行五个数 n , a 0 , a , b , p ( 1 ≤ n , a 0 , a , b , p ≤ 10000000 ) n,a0,a,b,p(1\le n,a0,a,b,p\le 10000000) n,a0,a,b,p(1n,a0,a,b,p10000000) 。 该数列的构造方法为, a [ i ] = ( a [ i − 1 ] × a + b ) a[i]=(a[i-1]\times a+b)%p a[i]=(a[i1]×a+b) 。该数列的下标为 1 ∼ n 1\sim n 1n

输出格式

1 1 1 行,表示答案。

输入样例1

4 1 1 1 3

输出样例1

10

输入样例2

10 7353044 9131079 2797084 5600580

输出样例2

606654815

基本思路

不难分析出题目就是要求长度 ≥ 2 \geq 2 2 的区间里最大值*次大值的和。

但是逐个枚举区间一定会超时,我们发现它只要最终的和,又没要每个区间的和,所以我们可以寻求一种整体的解法

要是我们能通过统计一个数出现次数的方式来求解的话复杂度可以得到很大的优化。

设序列中一个数为 n o w now now

n o w now now 之前第一个比他大的数的位置为 L 1 L1 L1 L 1 L1 L1 之前第一个比他大的数的位置为 L 2 L2 L2

n o w now now 之后第一个比他大的数的位置为 R 1 R1 R1 R 1 R1 R1 之后第一个比他大的数的位置为 R 2 R2 R2

那么对于 n o w now now ,其作为次大值存在的区间有:

1、左端点在 [ L 2 + 1 [L2+1 [L2+1 L 1 ] L1] L1] 之间,右端点在 [ n o w , R 1 − 1 ] [now,R1-1] [now,R11] 之间

2、左端点在 [ L 1 + 1 [L1+1 [L1+1 , (now]) 之间,右端点在 [ R 1 , R 2 − 1 ] [R1,R2-1] [R1,R21] 之间。

维护一个链表对应给出的序列,从小到大枚举数,枚举完就删除,这样能保证每次枚举的数是链表中最小的,并且可以 O ( 1 ) O(1) O(1) 得知 L 1 , L 2 , R 1 , R 2 L1,L2,R1,R2 L1,L2,R1,R2 的值

因为此题数据范围 n n n 1   1 e 7 1~1e7 1 1e7 ,最大值 p p p 范围在 1   1 e 7 1~1e7 1 1e7 ,所以考虑用基数排序优化排序的过程(但实际上 s o r t sort sort 也能过)。

这样时间复杂度为 O ( n ) O(n) O(n)

这题还有一个恶心的点就是有关于内存的问题,肯定是不能开 l o n g   l o n g long\ long long long 的,空间复杂度太大了,所以我们必须极其小心地控制它不溢出。我调了很久的一个地方是统计答案那里。
这是错误的代码:

ans=(ans+(cnt[tmp].d*cnt[L1].d%mod)*
	((R1-tmp)*(L1-L2)%mod))%mod;
ans=(ans+(cnt[tmp].d*cnt[R1].d%mod)*
	((tmp-L1)*(R2-R1)%mod))%mod;

正确的代码参考下面。说实话两种代码我看不出实质性的区别,但是上面那个好像溢出了。

核心代码

#include<bits/stdc++.h>
#define AC 0
#define val first
#define code second
using namespace std;
typedef unsigned long long ull;
typedef long long ll;
typedef pair<int,int> pii;
const int N=1e7+10;
const int MOD=1e9+7;
struct node{
	int d,prv,nxt;
}cnt[N];
int n,a0,a,b,p,L1,L2,R1,R2,tmp;
ll ans;
pii num[N];
inline void Omit(int add){
	cnt[cnt[add].prv].nxt=cnt[add].nxt;
	cnt[cnt[add].nxt].prv=cnt[add].prv;
}
bool cmp(pii x,pii y){
	if(x.val!=y.val) return x.val<y.val;
	return x.code>y.code;
}
inline void print(){
	for(int i=cnt[0].nxt;i!=n+1;i=cnt[i].nxt)
		cout<<cnt[i].d<<" ";
	cout<<endl;
}
int main(){
	ios::sync_with_stdio(false);
	cin>>n>>a0>>a>>b>>p;
	cnt[0].d=a0;
	for(register int i=1;i<=n;i++){
		num[i].val=cnt[i].d=(1ll*cnt[i-1].d*a+b)%p;
		cnt[i].prv=i-1;cnt[i].nxt=i+1;
		num[i].code=i;
	}
	sort(num+1,num+1+n,cmp);
	cnt[0].prv=0;cnt[n+1].nxt=n+1;
	for(register int t=1;t<=n;t++){
		tmp=num[t].code;
		L1=cnt[tmp].prv;R1=cnt[tmp].nxt;
		L2=cnt[L1].prv;R2=cnt[R1].nxt;
		ans = (ans + 1ll * cnt[L1].d * cnt[tmp].d % MOD * (L1 - L2) % MOD * (R1 - tmp) % MOD) % MOD;
        ans = (ans + 1ll * cnt[R1].d * cnt[tmp].d % MOD * (R2 - R1) % MOD * (tmp - L1) % MOD) % MOD;
		Omit(tmp);
	}
	cout<<ans;
	return AC;
}
  • 17
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值