国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 學院 > 開發設計 > 正文

算法訓練 Beaver's Calculator/codeforces 207A1 排序+貪心

2019-11-11 02:29:28
字體:
來源:轉載
供稿:網友
問題描述  從萬能詞典來的聰明的海貍已經使我們驚訝了一次。他開發了一種新的計算器,他將此命名為"Beaver's Calculator 1.0"。它非常特別,并且被計劃使用在各種各樣的科學問題中?! 榱藴y試它,聰明的海貍邀請了n位科學家,編號從1到n。第i位科學家給這個計算器帶來了 ki個計算題。第i個科學家帶來的問題編號1到n,并且它們必須按照編號一個一個計算,因為對于每個問題的計算都必須依賴前一個問題的計算結果。  每個教授的每個問題都用一個數 ai,?j? 來描述,i(1≤i≤n)是科學家的編號,j(1≤j≤ ki )是問題的編號, ai,?j? 表示解決這個問題所需資源單位的數量?! ∵@個計算器非常不凡。它一個接一個的解決問題。在一個問題解決后,并且在下一個問題被計算前,計算器分配或解放資源。  計算器中最昂貴的操作是解放資源,解放遠遠慢于分配。所以對計算器而言,每一個接下來的問題所需的資源不少于前一個,是非常重要的?! 〗o你關于這些科學家所給問題的相關信息。你需要給這些問題安排一個順序,使得“壞對”盡可能少。  所謂“壞對”,就是相鄰兩個問題中,后一個問題需求的資源比前一個問題少。別忘了,對于同一個科學家給出的問題,計算它們的相對順序必須是固定的。輸入格式  第一行包含一個整數n,表示科學家的人數。接下來n行每行有5個整數,ki, ai,?1, xi, yi, mi (0?≤?ai,?1?<?mi?≤?109, 1?≤?xi,?yi?≤?109) ,分別表示第i個科學家的問題個數,第1個問題所需資源單位數,以及3個用來計算 ai,?j 的參量。ai,?j?=?(ai,?j?-?1?*?xi?+?yi)mod mi。輸出格式  第一行輸出一個整數,表示最優順序下最少的“壞對”個數?! ∪绻麊栴}的總個數不超過200000,接下來輸出  行,表示解決問題的最優順序。每一行兩個用空格隔開的整數,表示這個問題所需的資源單位數和提供這個問題的科學家的編號。樣例輸入22 1 1 1 102 3 1 1 10樣例輸出01 12 13 24 2數據規模和約定  20%的數據 n?=?2, 1?≤?ki?≤?2000;  另外30%的數據 n?=?2, 1?≤?ki?≤?200000;

  剩下50%的數據 1?≤?n?≤?5000, 1?≤?ki?≤?5000。

思路:首先對于每個科學家我們知道他們k個問題的相對順序不能改變,所以對于每個科學家來說他們問題本身的順序就有可能存在壞對,由于題目中所說對于同一個科學家的問題,只要求相對順序不變,他們可以拆開插到別的科學家的問題之間.那么我們就可以設想,我們先分別記錄每個科學家本身問題順序的壞對的最大值,那么這個最大值是否可以作為問題的最后結果呢?答案是可以的,就按照以上提到的,我們可以將其余科學家的問題按照大小順序穿插在那個本身壞對數最大的科學家的問題之中而不產生新的壞對數.我們可以對這些問題進行分層,對于每個科學家第一次出現壞對時(如果沒有壞對就是整個序列)然后進行歸并排序.(這里也可以選擇其他穩定的排序方法,因為每個問題的相對順序不能改變 所以只能選擇穩定的排序)一直到第sum層。。。

證明:首先對于每一個科學家自身的序列來說,由于我們用的是歸并排序,所以絕對不會改變每一個科學家自身序列的相對順序。其次對于每一層的序列,我們經過排序后肯定是保證嚴格遞增的(即不存在壞對),對于下一層的序列來說同樣如此,由于下一層的序列的問題中和上一層的序列的問題中至少存在著一個壞對,所以對于下一層的第一個數(也是最小的那個數)必定是小于上一層的最后一個數的,也就是說保證了2層之間有一個壞對數。那么最終答案就是sum個壞對數,也就是最少的壞對數。

#include<iostream>#include<cstdio>#include<cstring>#include<algorithm>#define ll long long#define N 200010using namespace std;struct tc{	int cnt,count;//cnt下標 count 問題數量	ll p[5001];}q[5001];struct sc{	int id;//下標	ll num;//消耗}anss[N],s[N];void merge(int l,int mid,int r)//歸并排序{	int i=l,j=mid+1;	int cc=l;	while(i<=mid&&j<=r)	{		if(anss[i].num<=anss[j].num)		{			s[cc].id=anss[i].id;			s[cc++].num=anss[i++].num; 		}		else		{			s[cc].id=anss[j].id;			s[cc++].num=anss[j++].num; 		}	}	while(i<=mid)	{			s[cc].id=anss[i].id;			s[cc++].num=anss[i++].num; 	}	while(j<=r)	{			s[cc].id=anss[j].id;			s[cc++].num=anss[j++].num; 	}	for(i=l;i<cc;i++)	{			anss[i].id=s[i].id;			anss[i].num=s[i].num;	}		return ;}void mergesort(int x,int y){	if(x<y)	{		int mid=(x+y)/2;		mergesort(x,mid);		mergesort(mid+1,y);		merge(x,mid,y); 	}	return ;}int main(){	int i,j;	ll n,a,x,y,m;	int ans=-1,k,sum,l=0;	cin>>n;	for(i=0;i<n;i++)	{		scanf("%d %I64d %I64d %I64d %I64d",&k,&a,&x,&y,&m);		sum=0;		l+=k;		q[i].cnt=1;		q[i].count=k;		q[i].p[1]=a; 		for(j=2;j<=k;j++)		{			q[i].p[j]=(x*q[i].p[j-1]+y)%m;			if(q[i].p[j]<q[i].p[j-1])			sum++;		}		ans=max(ans,sum);//找最大	}	PRintf("%d/n",ans);	int st=0,end=0;	while(end<l)	{		for(i=0;i<n;i++)//分層歸并排序		{			for(j=q[i].cnt;j<=q[i].count;j++)			{				if(j!=q[i].cnt&&q[i].p[j]<q[i].p[j-1])// 每一層的第一個j 不能和前一個比較				{ q[i].cnt=j;				  break;				}				anss[end].id=i;				anss[end++].num=q[i].p[j];			}			if(j>q[i].count)//如果沒有壞對就是整個序列			q[i].cnt=j;		}		mergesort(st,end-1);		st=end;	}	for(i=0;i<l;i++)	printf("%I64d %d/n",anss[i].num,anss[i].id+1);	return 0;}

下面說一下對于這道題一個非常巧妙的方法,把兩個方法放在一起.兩個問題的思想完全一樣 都是進行分層排序,我們上一個是采用的分層歸并排序,這里思想非常巧妙?。?!

利用結構體并且+快排直接分層排序

#include<iostream>#include<cstdio>#include<cstring>#include<algorithm>#define ll long longusing namespace std;ll n,a,k,x,y,m,b;struct node{	int x,y,z;//x 表示層數 y 表示的是所需資源單位數  z表示的是科學家的編號}p[200010];int cmp(node w,node l)//這里非常巧妙!如果層數相等 在同一層里我們就按照所需資源單位數排序,如果資源單位數相同就按照科學家
//編號排序,否則就按照層數排序{	if(w.x==l.x)		return w.y<l.y||(w.y==l.y&&w.z<l.z);	return w.x<l.x; }int main(){	int i,j;	int ans=-1,cnt=0;	cin>>n;	for(i=1;i<=n;i++)	{		int t=0;//t 計算為第幾層,這里都一樣我們還是按照壞對來分層出現一次為一層,沒有壞對就是整個序列		scanf("%I64d %I64d %I64d %I64d %I64d",&k,&a,&x,&y,&m);			for(j=1;j<=k;j++)//這里是分層的關鍵!		{				p[cnt++]=(node){t,a,i};				b=(x*a+y)%m;				if(b<a&&j!=k)//第k個問題沒有最后一個b				t++;				a=b;		}		ans=max(ans,t);	}	printf("%d/n",ans);	sort(p,p+cnt,cmp);	for(i=0;i<cnt;i++)	{		printf("%d %d/n",p[i].y,p[i].z);	}	return 0;}


發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 苏尼特右旗| 平邑县| 云南省| 万年县| 穆棱市| 育儿| 黎城县| 龙里县| 丹棱县| 项城市| 精河县| 南阳市| 湖南省| 宜兰市| 尚志市| 三原县| 博乐市| 贵德县| 荣昌县| 上虞市| 盐山县| 仁化县| 巴彦淖尔市| 扎鲁特旗| 监利县| 万山特区| 六安市| 贺州市| 长寿区| 和田县| 府谷县| 达孜县| 威远县| 盐源县| 夹江县| 辽宁省| 商洛市| 钟山县| 湖北省| 开阳县| 秭归县|