2020 Multi-University Training Contest 10 hdu6883 Coin Game(思维题 贪心)

题目

2020 Multi-University Training Contest 10 hdu6883 Coin Game(思维题 贪心)_第1张图片

多组样例,n(n<=5e6)种机器,第i种机器有ai和bi两个权值,用上述算法生成,其中参数1<=k1,k2<=1e12

对于第i种机器,你可以按一次按钮获得ai收益,可以再按一次再获得bi收益,可以再按第三次获得ai收益,最多按三次

记f(x)为只能按x次按钮的最大收益和,

求f(1)^f(2)^...^f(m)(m<=1.5e7),其中^表示异或

思路来源

官方题解

心得

赛中一直考虑1、2、3三种怎么互斥背包,然而1.5e7决定了只能用线性做,

感觉主要是没想到拆成两个无关的物品然后贪心吧

题解

考虑第i种,1次ai,2次ai+bi,3次ai+(ai+bi),

可以拆成两个约束无关的物品,一个(1,ai),一个(2,ai+bi),对应次数和权值

 

如果考虑用平均值最高的物品凑出x次,则可能凑出的是x+1次,

此时一个2次数的平均比一个1次数的更优,

这种情况下,把已经取的2次数的平均最小的去掉,把1次数的还没取的最大的加上,就是f(x)的值,

 

因此,可以考虑递推,f(x)从f(x-1)次递推而来,

要么,选择一个还没取的权值最大的1次,

要么,把已经取的2次的权值最小的去掉,把1次数的还没取的最大的加上

复杂度O(nlogn+m)

代码

#include
using namespace std;
typedef unsigned long long ull;
typedef long long ll;
const int N=5e6+10,M=15e6+10,mod=1e9+7;
const int mx=10000000;
ull k1,k2;
int t,n,m,a[N],b[N];
ll ans,now;
ull xorS(){
    ull k3=k1,k4=k2;
    k1=k4;
    k3^=(k3<<23);
    k2=k3^k4^(k3>>17)^(k4>>26);
    return k2+k4;
}
void gen(int n,ull _k1,ull _k2){
    k1=_k1,k2=_k2;
    for(int i=1;i<=n;++i){
        a[i]=xorS()%mx+1;
        b[i]=xorS()%mx+1;
    }
}
int main(){
    while(~scanf("%d%d%llu%llu",&n,&m,&k1,&k2)){
        gen(n,k1,k2);
        for(int i=1;i<=n;++i){
            b[i]=a[i]+b[i];
        }
        sort(a+1,a+n+1,greater());
        sort(b+1,b+n+1,greater());
        ans=a[1];now=a[1];
        int na=1,nb=0;
        for(int i=2;i<=m;++i){
            ll v1=0,v2=0;
            if(na+1<=n){
                v1=now+a[na+1];
            }
            if(na-1>=0 && nb+1<=n){
                v2=now-a[na]+b[nb+1];
            }
            if(v1>v2){
                na++;
                now=v1;
            }
            else{
                na--;
                nb++;
                now=v2;
            }
            ans^=now;
        }
        printf("%lld\n",ans);
    }
    return 0;
}

 

你可能感兴趣的:(思维题,#,杭电多校,思维题,递推)