硬币游戏

硬币游戏

笔者由于找不到原题就自己造了数据

题目描述

给定 n n n 组硬币,每组有3个,第 i i i组从上到下价值依次为 a i , b i , a i a_{i},b_{i},a_{i} ai,bi,ai.

对于每个 k ∈ [ 1 , 3 n ] k\in [1,3n] k[1,3n],请给出取 k k k枚硬币可以得到的最大价值。 ( n ⩽ 1 0 7 ) (n\leqslant 10^7) (n107)

题解

我们考虑把每组硬币分解成 a i a_{i} ai a i + b i a_{i}+b_{i} ai+bi两部分,这样可以完美的凑出取在第 i i i组取 0 , 1 , 2 , 3 0,1,2,3 0,1,2,3枚硬币的情况。

前面 a i a_{i} ai的消耗为 1 1 1,后面 a i + b i a_{i}+b_{i} ai+bi的消耗为 2 2 2。我们就先将 a i + b i a_{i}+b_{i} ai+bi化成 a i + b i 2 \frac{a_{i}+b_{i}}{2} 2ai+bi,将两部分一起排序,贪心的取。

由于可能会存在第二部分取一半的情况,我们就在取一半时分舍掉前一个一枚,取后面的一个两枚与直接去后面的一个一枚两种情况特判一下。就这样一直一个一个的取下去,就可以枚举完 [ 1 , 3 n ] [1,3n] [1,3n]的情况了。

源码

#include<cstdio>
#include<cmath>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<queue>
using namespace std;
#define MAXN 10000005
#define lowbit(x) (x&-x)
#define reg register
typedef long long LL;
typedef unsigned long long uLL;
typedef pair<int,int> pii;
const int INF=0x7f7f7f7f;
template<typename _T>
_T Fabs(_T x){return x<0?-x:x;}
template<typename _T>
void read(_T &x){
	_T f=1;x=0;char s=getchar();
	while(s>'9'||s<'0'){if(s=='-')f=-1;s=getchar();}
	while('0'<=s&&s<='9'){x=(x<<3)+(x<<1)+(s^48);s=getchar();}
	x*=f;
}
int n,a[MAXN],b[MAXN],p1,p2,p3,p4,p5,p6,pow10[10];LL ans,las;
vector<int> vec[1005];
void Sort(int *A){
	for(reg int i=0;i<10;i+=3){
		for(reg int j=1;j<=n;++j){
			int d=A[j]/pow10[i];d=d-d/1000*1000;
			vec[d].push_back(A[j]);	
		}
		int now=0;
		for(reg int j=999;j>=0;--j){
			int siz=vec[j].size();
			for(reg int k=0;k<siz;++k)A[now+k+1]=vec[j][k];
			now+=siz;vec[j].clear();
		}
	}
}
signed main(){
	pow10[0]=1;for(reg int i=1;i<10;++i)pow10[i]=10*pow10[i-1];
	read(n);int lasx,lasy;read(lasx);read(lasy);
	read(p1);read(p2);read(p3);read(p4);read(p5);read(p6);
	a[1]=lasx;b[1]=lasx+lasy;
	for(reg int i=1;i<=n;++i){
		lasx=1ll*lasx*p1%p2+p3;
		lasy=1ll*lasy*p4%p5+p6;
		a[i]=lasx;b[i]=lasx+lasy;
	}
	Sort(a);Sort(b);
	int ida=0,idb=0,sum=0;LL num=0;
	for(reg int i=1;i<=3*n;++i){
		if(1.0*a[ida+1]>1.0*b[idb+1]/2.0)
			ida++,sum++,num+=1ll*a[ida],ans^=num;
		else{
			if(sum+2==i)
				idb++,sum+=2,num+=1ll*b[idb],ans^=num;
			else{
				LL tmp=num;if(ida>0&&idb<n)tmp=max(num-1ll*a[ida]+1ll*b[idb+1],tmp);
				if(ida<n)tmp=max(num+1ll*a[ida+1],tmp);ans^=tmp;
			}
		}
	}
	printf("%lld\n",ans);
	return 0;
}

谢谢!!!

posted @ 2021-02-17 22:13  StaroForgin  阅读(22)  评论(0)    收藏  举报  来源