题解:CF207A1 Beaver's Calculator 1.0

两种做法。

dp 做法

我们设 dpi,j,0/1dp_{i,j,0/1} 为第一个序列 aa 取了 ii 个,第二个序列 bb 取了 jj 个,上一个数取自 aa(最后一维为 00)或 bb(最后一维为 11)的最小答案。

不难发现答案就是 dpk1,k2dp_{k_1,k_2}

转移方程也很显然,因为 dpi,j,0dp_{i,j,0} 一定由 dpi1,j,0/1dp_{i-1,j,0/1} 转移来,把这一个元素和上一个状态的最后一个元素比较即可,方程为:

dpi,j,0=min(dpi1,j,0+[ai>ai1],dpi1,j,1+[ai>bj])dp_{i,j,0}=\min(dp_{i-1,j,0}+[a_i>a_{i-1}],dp_{i-1,j,1}+[a_i>b_j])

dpi,j,1dp_{i,j,1} 的转移方程大致与此相同,为:

dpi,j,1=min(dpi,j1,0+[bj>ai],dpi1,j,1+[bj>bj1])dp_{i,j,1}=\min(dp_{i,j-1,0}+[b_j>a_i],dp_{i-1,j,1}+[b_j>b_{j-1}])

代码很好写。但是这个做法仅能通过 A1。

贪心做法

这也是可以通过 A2 和 A3 的正解做法。

我们把 aa 序列分成 cntcnt 个不下降的子段。

例如:a={1,1,4,5,1,4,1,9,1,9,8,1}a=\{1,1,4,5,1,4,1,9,1,9,8,1\},则分成 {1,1,4,5}\{1,1,4,5\}{1,4}\{1,4\},{1,9}\{1,9\},{1,9}\{1,9\},{8}\{8\}1166 个子段。

bb 序列同理。

很显然,如果有 kk(这里 k=2k=2)个不下降序列,它们一定可以通过归并变成不下降的子序列,如果要从小到大取,这个过程中只会取到每个序列的头部元素。

证明一下:如果取到了元素 ii,那么 i1i-1 号元素一定比它小,更靠前。所以从每个序列的头部取最好。

我们也可以忽视这个取头部元素的要求,直接使用一个优先队列去维护。

所以有两种写法。

注意到优先队列默认是大根堆,所以我们可以把元素值取反扔进一个 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。

posted @   Weslie_qwq  阅读(4)  评论(0编辑  收藏  举报  
相关博文:
阅读排行:
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】
点击右上角即可分享
微信分享提示