洛谷P1080(NOIP2012)国王游戏——贪心排序与高精度

题目:https://www.luogu.org/problemnew/show/P1080

排序方法的确定,只需任取两个人,通过比较与推导,可以得出ai*bi小的人排在前面;

高精度写的时候犯了些细节错误,详见注释。

代码如下:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define MAXN 200005
using namespace std;
typedef long long ll;//用long long!
ll n,ka,kb,ans[MAXN],tmp[MAXN],tmp2[MAXN],c[MAXN];
struct N{
    ll a,b;
}p[1005];
bool cmp(N x,N y)
{
    return x.a*x.b<y.a*y.b;
}
void chu(ll a[],ll b)
{
    ll x=0;
    c[0]=a[0];
    for(ll i=a[0];i>0;i--)//倒序存储,正序除
    {
        c[i]=(x*10000+a[i])/b;
        x=(x*10000+a[i])%b;
    }
    while(c[c[0]]==0&&c[0]>0)c[0]--;
}
void ch(ll a[],ll b)
{
    ll x=0;
    for(ll i=1;i<=a[0];i++)//倒序乘
    {
        a[i]*=b;a[i]+=x;
        x=a[i]/10000;
        a[i]%=10000;
    }
    while(x)a[0]++,a[a[0]]=x%10000,x/=10000;
}
int com(ll a[],ll b[])
{
    if(a[0]>b[0])return 1;
    if(a[0]<b[0])return -1;
    for(ll i=a[0];i;i--)//倒序!
        if(a[i]>b[i])return 1;
    return 0;
}
void print(ll a[])
{
//    if(a[a[0]]==0)//?
//    {
//        printf("1");
//        return;
//    }
    printf("%lld",a[a[0]]);
    for(ll i=a[0]-1;i>0;i--)
    {
        printf("%lld",a[i]/1000);
        a[i]%=1000;
        printf("%lld",a[i]/100);
        a[i]%=100;
        printf("%lld",a[i]/10);
        a[i]%=10;
        printf("%lld",a[i]);
    }
}
int main()
{
    scanf("%lld%lld%lld",&n,&ka,&kb);
    for(ll i=1;i<=n;i++)
        scanf("%d%d",&p[i].a,&p[i].b);
    sort(p+1,p+n+1,cmp);
    tmp[0]=1;tmp[1]=ka;//压位
    for(ll i=1;i<=n;i++)
    {
        memcpy(tmp2,tmp,sizeof tmp);
        memset(c,0,sizeof c);
        chu(tmp2,p[i].b);
        if(com(c,ans)>0)memcpy(ans,c,sizeof c);//必须>0,否则-1也会被算!
        ch(tmp,p[i].a);
    }
    print(ans);
    return 0;
}

这个运行起来有点慢,有些地方写得不够好,下面有一篇运行很快的代码,可以比较看看提速的方法。

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
const int INF=10000;
typedef long long ll;
ll n,gb,ljc[1005],max,tmp[1005],ans[1005];
char tp[5];
struct Node{
    ll a,b,w;
}r[1005];
bool cmp(Node x,Node y)
{
    return x.w<y.w;
}
void chu(ll b)
{
    ll x=0;
    tmp[0]=ljc[0];
    for(ll i=ljc[0];i;i--)
    {
        ll s=ljc[i]+x*INF;
        tmp[i]=s/b;
        x=s%b;
    }
    while(!tmp[tmp[0]]&&tmp[0]>1)tmp[0]--;
}
bool comp(ll ans[],ll b[])
{
    if(ans[0]>b[0])return 0;
    if(ans[0]<b[0])return 1;
    for(ll i=ans[0];i;i--)
    {
        if(ans[i]>b[i])return 0;
        if(ans[i]<b[i])return 1;
    }
    return 0;
}
void mul(ll a)
{
    ll x=0;
    for(ll i=1;i<=ljc[0];i++)
    {
        ll s=ljc[i]*a+x;
        x=s/INF;
        ljc[i]=s%INF;
    }
    if(x)ljc[0]++,ljc[ljc[0]]=x;//至多进一位
}
int main()
{
    scanf("%lld%lld%lld",&n,&ljc[1],&gb);
    ljc[0]=1;
    for(ll i=1;i<=n;i++)
    {
        scanf("%lld%lld",&r[i].a,&r[i].b);
        r[i].w=r[i].a*r[i].b;
    }
    sort(r+1,r+n+1,cmp);
    for(ll i=1;i<=n;i++)
    {
        memset(tmp,0,sizeof tmp);
        chu(r[i].b);
        if(comp(ans,tmp))memcpy(ans,tmp,sizeof tmp);
        mul(r[i].a);
    }
    printf("%lld",ans[ans[0]]);
    for(ll i=ans[0]-1;i;i--)
    {
        printf("%lld",ans[i]/1000);
        printf("%lld",ans[i]/100%10);
        printf("%lld",ans[i]/10%10);
        printf("%lld",ans[i]%10);
    }
    return 0;
}

原文地址:https://www.cnblogs.com/Zinn/p/8531302.html

时间: 2024-08-02 12:11:01

洛谷P1080(NOIP2012)国王游戏——贪心排序与高精度的相关文章

【洛谷P1080】国王游戏

我们按照左右手数的乘积升序排序,就能使最多金币数最小了 为什么呢? 我们知道: 1)如果相邻的两个人交换位置,只会影响到这两个人的值,不会影响他人 2)假设相邻的两个人i, i + 1.设A[i] B[i] <= A[i + 1] B[i + 1],i之前所有人的左手乘积为S. ans1 = max{S / B[i], S * A[i] / B[i + 1]} ans2 = max{S / B[i + 1], S * A[i + 1] / B[i]} 因为,A[i] B[i] <= A[i +

洛谷P1080 [NOIP2012提高组D1T2]国王游戏 [2017年5月计划 清北学堂51精英班Day1]

P1080 国王游戏 题目描述 恰逢 H 国国庆,国王邀请 n 位大臣来玩一个有奖游戏.首先,他让每个大臣在左.右 手上面分别写下一个整数,国王自己也在左.右手上各写一个整数.然后,让这 n 位大臣排 成一排,国王站在队伍的最前面.排好队后,所有的大臣都会获得国王奖赏的若干金币,每 位大臣获得的金币数分别是:排在该大臣前面的所有人的左手上的数的乘积除以他自己右 手上的数,然后向下取整得到的结果. 国王不希望某一个大臣获得特别多的奖赏,所以他想请你帮他重新安排一下队伍的顺序, 使得获得奖赏最多的大

洛谷P1080 国王游戏 高精度 贪心 数学推公式

洛谷P1080 国王游戏        数学推公式      高精度    贪心 然而这并不是我打出来的,抄题解... 将左手与右手的乘积从小到大排序,然后计算求最大值即可.(需要高精度) 证明: 1)知道,如果相邻的两个人交换位置,只会影响到这两个人的值,不会影响他人 2)假设相邻的两个人i, i + 1.设A[i] B[i] <= A[i + 1] B[i + 1],i之前所有人的左手乘积为S. 则,ans1 = max{S / B[i], S * A[i] / B[i + 1]} 若交换

洛谷P1118 数字三角形游戏

洛谷1118 数字三角形游戏 题目描述 有这么一个游戏: 写出一个1-N的排列a[i],然后每次将相邻两个数相加,构成新的序列,再对新序列进行这样的操作,显然每次构成的序列都比上一次的序列长度少1,直到只剩下一个数字位置.下面是一个例子:     3   1   2   4       4   3   6         7   9          16 最后得到16这样一个数字. 现在想要倒着玩这样一个游戏,如果知道N,知道最后得到的数字的大小sum,请你求出最初序列a[i],为1-N的一个

洛谷P1290 欧几里德的游戏 数学 博弈论 模拟

洛谷P1290 欧几里德的游戏 数学 博弈论 模拟 这道题我们因为当 x 大于 y 时 你也只能在合法范围 内取 1 个 y 两个 y 也就是说 能取的y大于等于2时,则你本质不同的取法共有两种,此时你必定获胜,因为本质不同,而在最优策略下,则说明胜利者也不同,也就是说这时候你可以决定自己的输赢 ,我们称这种必胜局为 v 局 2.但是如果 v 局后面还有v 局怎么办,这个不必担心,因为先拿到 v局的人,有两种本质不同的取法,也就是说 他可以控制自己下次必定拿到 v 局,这样就 能确保胜利了 所以

洛谷1288 取数游戏II 博弈论

洛谷1288 取数游戏II 博弈论 最优策略 一定是你一步把值走完,然后我再走完,这样不给别人留后路 然后这样走 只要自己从左走 或者从右走其中有一个有奇数步可走,则说明是必胜局 如果都是只能走偶数步的,就是必败局 . 另一个题解 首先,对于一条链a1,a2,a3,a4......0 如果是偶数条边,那么现手一定赢,因为他每一次都只用把后面一条取完,例如 5 4 3 6 5 0 先手取完5,后手没法回到前一个位置,而无论接下来后手去多少,先手继续取完3,再然后取完5,后手没办法再去,先手赢.就这

洛谷P1082/NOIP2012 同余方程

洛谷P1082/NOIP2012 同余方程 题目描述 求关于 x 的同余方程 ax ≡ 1 (mod b)的最小正整数解. 输入输出格式 输入格式: 输入只有一行,包含两个正整数 a, b,用一个空格隔开. 输出格式: 输出只有一行,包含一个正整数 x0,即最小正整数解.输入数据保证一定有解. 输入输出样例 输入样例#1: 复制 3 10 输出样例#1: 复制 7 说明 [数据范围] 对于 40%的数据,2 ≤b≤ 1,000: 对于 60%的数据,2 ≤b≤ 50,000,000: 对于 10

AC日记——国王游戏 洛谷 P1080

国王游戏 思路: 贪心+高精: 代码: #include <bits/stdc++.h> using namespace std; #define maxn 1005 struct DataType { int a,b,key; bool operator<(const DataType pos)const { return key<pos.key; } }; struct DataType ai[maxn]; struct BintType { int len; char ch[

NOIP2012国王游戏

  题目描述 恰逢 H 国国庆,国王邀请 n 位大臣来玩一个有奖游戏.首先,他让每个大臣在左.右 手上面分别写下一个整数,国王自己也在左.右手上各写一个整数.然后,让这 n 位大臣排 成一排,国王站在队伍的最前面.排好队后,所有的大臣都会获得国王奖赏的若干金币,每 位大臣获得的金币数分别是:排在该大臣前面的所有人的左手上的数的乘积除以他自己右 手上的数,然后向下取整得到的结果. 国王不希望某一个大臣获得特别多的奖赏,所以他想请你帮他重新安排一下队伍的顺序, 使得获得奖赏最多的大臣,所获奖赏尽可能