题解:P6979 [NEERC2015] Generators
[NEERC2015] Generators
题意
有
思路
-
显然
ax+b 是单调不减的,那么对c 取模就是周期函数,只需求出一个周期即可代表整个序列。 -
对每个序列记录对
k 取模后值不同的最大值和次大值。 -
将每个序列最大值累加,若对
k 取模不为0 ,那么输出。 -
否则考虑将一个最大值替换成次大值,要求前后差值最小。
- 若能替换,则替换后对
k 取模一定不为0 ,进行输出。 - 若不能替换,则意味着无解,输出
-1 。
- 若能替换,则替换后对
代码
#include<bits/stdc++.h>
#define ll long long
using namespace std;
ll n, mod;
ll x, a, b, c, ans;
ll vis[10005]; //存储序列元素下标
struct node {
ll index, value; //下标和值
}q[10005][2]; //0为最大值,1为次大值
void Make_serial() {
memset(vis, 0, sizeof(vis));
for(int i=1; !vis[x]; i++) {
vis[x]=i;
x=(a*x+b)%c;
}
}
void Get_max(ll i) {
q[i][0].index=q[i][1].index=q[i][0].value=q[i][1].value=-1;
for(int j=c-1; j>=0; j--) {
if(!vis[j]) continue;
if(j>=q[i][0].value) { //可以更新最大值
if(j%mod!=q[i][0].value%mod) q[i][1]=q[i][0]; //尝试用之前最大值替换次大值
q[i][0].value=j, q[i][0].index=vis[j];
} else if(j>q[i][1].value&&j%mod!=q[i][0].value%mod) { //可以更新次大值
q[i][1].value=j, q[i][1].index=vis[j];
}
if(q[i][0].value!=-1&&q[i][1].value!=-1) break; //最大值和次大值都有了,结束
}
}
void Get_ans() {
for(int i=1; i<=n; i++) ans+=q[i][0].value; //求最大值累加和
if(ans%mod) { //取模不为0,输出
cout << ans << "\n";
for(int i=1; i<=n; i++) cout << q[i][0].index-1 << " ";
} else {
ll idx=0; q[0][0].value=0x7f7f7f7f7f, q[0][1].value=0;
for(int i=1; i<=n; i++) { //找到替换后差值最小的序列编号
if(q[i][1].value==-1) continue;
if(q[i][0].value-q[i][1].value<q[idx][0].value-q[idx][1].value) idx=i;
}
if(idx==0) { //不能替换
cout << -1;
return;
}
ans=ans-q[idx][0].value+q[idx][1].value; //更新替换后的答案
cout << ans << "\n";
q[idx][0]=q[idx][1]; //更新替换后的编号
for(int i=1; i<=n; i++) cout << q[i][0].index-1 << " ";
}
}
int main(){
cin >> n >> mod;
for(int i=1; i<=n; i++) {
cin >> x >> a >> b >> c;
Make_serial();
Get_max(i);
}
Get_ans();
return 0;
}