题解:CF207A1 Beaver's Calculator 1.0
两种做法。
dp 做法
我们设 为第一个序列 取了 个,第二个序列 取了 个,上一个数取自 (最后一维为 )或 (最后一维为 )的最小答案。
不难发现答案就是 。
转移方程也很显然,因为 一定由 转移来,把这一个元素和上一个状态的最后一个元素比较即可,方程为:
的转移方程大致与此相同,为:
代码很好写。但是这个做法仅能通过 A1。
贪心做法
这也是可以通过 A2 和 A3 的正解做法。
我们把 序列分成 个不下降的子段。
例如:,则分成 ,,,, 和 共 个子段。
序列同理。
很显然,如果有 (这里 )个不下降序列,它们一定可以通过归并变成不下降的子序列,如果要从小到大取,这个过程中只会取到每个序列的头部元素。
证明一下:如果取到了元素 ,那么 号元素一定比它小,更靠前。所以从每个序列的头部取最好。
我们也可以忽视这个取头部元素的要求,直接使用一个优先队列去维护。
所以有两种写法。
注意到优先队列默认是大根堆,所以我们可以把元素值取反扔进一个 pair 里,大大降低了细节量。
// LUOGU_RID: 169816182
#include<bits/stdc++.h>
using namespace std;
int dp[2005][2005][2];
int n;
int k[3];
long long x,y,a[2005][2005],m;
int duan[2005][2005],cnt[2005],now[2005];
int pan(long long a,long long b){
if(a>=b)return 0;
return 1;
}
//int cnt=0;
priority_queue<pair<long long,int> >q;
signed main(){
cin>>n;
cin>>k[1]>>a[1][1]>>x>>y>>m;
for(int i=2;i<=k[1];i++){
a[1][i]=(a[1][i-1]*x+y)%m;
if(a[1][i]<a[1][i-1]){
duan[1][++cnt[1]]=i-1;
}
}
cin>>k[2]>>a[2][1]>>x>>y>>m;
for(int i=2;i<=k[2];i++){
a[2][i]=(a[2][i-1]*x+y)%m;
if(a[2][i]<a[2][i-1]){
duan[2][++cnt[2]]=i-1;
}
}
duan[1][++cnt[1]]=k[1];
duan[2][++cnt[2]]=k[2];
// cout<<duan[2][1]<<' '<<duan[2][2]<<' '<<duan[2][3]<<endl;
cout<<max(cnt[1],cnt[2])-1<<endl;
for(int i=1;i<=n;i++)now[i]=1;
for(int i=1;i<=max(cnt[1],cnt[2]);i++){
for(int j=1;j<=n;j++){
// j=2;
if(cnt[j]<i)continue;
// cout<<j<<' '<<i<<' '<<now[j]<<endl;
for(;now[j]<=duan[j][i];now[j]++){
// cout<<j<<' '<<now[j]<<endl;
pair<long long,int>ans;
ans.first=-a[j][now[j]];
ans.second=j;
q.push(ans);
}
}
while(!q.empty()){
cout<<-q.top().first<<' '<<q.top().second<<endl;
q.pop();
}
}
return 0;
}
A2 题更改数据范围即可,A3 题此代码会 MLE。

浙公网安备 33010602011771号