硬币游戏
硬币游戏
题目描述
给定 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) (n⩽107)
题解
我们考虑把每组硬币分解成 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;
}

浙公网安备 33010602011771号