[Daimayuan]新国王游戏(C++,数学)

Posted WitheredSakura_

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[Daimayuan]新国王游戏(C++,数学)相关的知识,希望对你有一定的参考价值。

又到了 H H H 国国庆, 国王再次邀请 n n n 位大臣来玩有奖游戏。上次国庆被众臣吐槽国王小气后,国王决定今年大方点,改变游戏规则且不再参与游戏,免得被大臣们质疑。首先, 他让每位大臣在左、 右手上面分别写下一个正整数。然后让这 n n n 位大臣排成一排。排好队后, 所有的大臣都会获得国王奖赏的若千金币, 每位大臣获得的金币数分别是:排在该大臣后面的所有人的左手上的数的乘积乘以他自己右手上的数。国王希望所有大臣获得的金币数之和最多,所以他想请你帮他重新安排一下队伍的顺序。

简而言之,给定 n n n 对数 a i , b i a_i,b_i ai,bi,找到一种排列顺序,使得 b 1 × a 2 ∗ a 3 ∗ … a n + b 2 × a 3 ∗ a 4 ∗ … a n + ⋯ + b n b_1×a_2∗a_3∗…a_n+b_2×a_3∗a_4∗…a_n+⋯+b_n b1×a2a3an+b2×a3a4an++bn 最大,求最大值,由于答案可能很大,需要对 1000000007 1000000007 1000000007 取模

输入格式:

第一行,包含一个整数 n n n。 第二行到第 n + 1 n+1 n+1 行,包含两个整数 a i , b i a_i,b_i ai,bi

输出格式:

输出一行,表示按某种排序后的 b 1 × a 2 ∗ a 3 ∗ … a n + b 2 × a 3 ∗ a 4 ∗ … a n + ⋯ + b n b_1×a_2∗a_3∗…a_n+b_2×a_3∗a_4∗…a_n+⋯+b_n b1×a2a3an+b2×a3a4an++bn 的最大值对 1000000007 1000000007 1000000007 取模的结果

样例输入

2
1 2
3 4

样例输出

10

说明

只有两种情况:

1. 1. 1.

1 2
3 4

( 2 ∗ 3 ) + 4 = 10 (2∗3)+4=10 (23)+4=10

2. 2. 2.

3 4
1 2

( 4 ∗ 1 ) + 2 = 6 ( 4 ∗ 1 ) + 2 = 6 (4∗1)+2=6(4∗1)+2=6 (41)+2=6(41)+2=6

所以答案为 10 10 10

数据限制

对于 100 100 100% 的数据,保证 1 ≤ n ≤ 1 0 6 1≤n≤10^6 1n106, 1 ≤ a i , b i ≤ 2 30 1≤a_i,b_i≤2^30 1ai,bi230

解题思路

思路很简单:先排序,然后累加求和

解题关键在于如何排序

采用算法sort()进行排序,我们需要做的就是重载比较运算符,而重载比较运算符,我们就只需要考虑一种简单的比较情形:相邻对换

对于 i , i + 1 i,i+1 i,i+1两位大臣,我们不需要考虑其 i i i前面的人和 i + 1 i+1 i+1后面的人,因为他们的顺序是不变的

我们只需要考虑两位大臣调换前后二者获取的金币变多了还是变少了

在调换之前: b i ∗ a i + 1 + b i + 1 b_i*a_i+1+b_i+1 biai+1+bi+1

在调换之后: b i + 1 ∗ a i + b i b_i+1*a_i+b_i bi+1ai+bi

比较二者的大小即可知道哪种排序获得的金币更多

AC代码如下

#include <iostream>
#include <algorithm>
#include <cmath>
using namespace std;
const int max_n = 1e6;
const int max_ab = pow(2, 30);
const int mod_num = 1000000007;

struct person  long long l, r; persons[max_n + 1];

int main() 
	int n;
	cin >> n;
	for (int i = 1; i <= n; i++) cin >> persons[i].l >> persons[i].r;
	sort(persons + 1, persons + 1 + n, [](person p1, person p2) 
		return p1.r * p2.l + p2.r > p2.r * p1.l + p1.r;
		);
	long long ans = 0;
	long long sum = 1;
	for (int i = n; i > 0; i--) 
		ans = (ans + persons[i].r * sum) % mod_num;
		sum = (sum * persons[i].l) % mod_num;
	
	cout << ans << endl;
	return 0;


洛谷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]}

若交换

则,ans2 = max{S / B[i + 1], S * A[i + 1] / B[i]}

因为,A[i] B[i] <= A[i + 1] B[i + 1]

所以,S A[i] / B[i + 1] <= S A[i + 1] / B[i]

又因为,S / B[i + 1] <= S * A[i] / B[i + 1]

所以,ans2 = S * A[i + 1] / B[i]

ans1 = max{S / B[i], S * A[i] / B[i + 1]}

所以,ans1 <= ans2

证毕 至于高精度:

由题意知,0 < a,b < 10000,所以用10000进制的高精度进行运算就可以了

转自 新浪博客

 

  1 #include<cstdio>  
  2 #include<cstdlib>  
  3 #include<cstring>  
  4 #include<cmath>  
  5 #include<ctime>  
  6 #include<iostream>  
  7 #include<algorithm>  
  8 using namespace std;  
  9 int N;  
 10 int a[1005],b[1005],ka,kb;  
 11 int ans[20000],t[20000],lena,lent,tt[20000],t2[20000],len;  
 12 void _qst_ab(int l,int r)  
 13 {  
 14     int i=l,j=r,ma=a[(i+j)>>1],mb=b[(i+j)>>1];  
 15     while(i<=j)  
 16     {  
 17         while(a[i]*b[i]<ma*mb) i++;  
 18         while(a[j]*b[j]>ma*mb) j--;  
 19         if(i<=j)  
 20         {  
 21             swap(a[i],a[j]);  
 22             swap(b[i],b[j]);  
 23             i++;j--;  
 24         }  
 25     }  
 26     if(l<j) _qst_ab(l,j);  
 27     if(i<r) _qst_ab(i,r);  
 28 }  
 29 void _init()  
 30 {  
 31     scanf("%d%d%d",&N,&a[0],&b[0]);  
 32     for(int i=1;i<=N;i++)  
 33         scanf("%d%d",&a[i],&b[i]);  
 34 }  
 35 void _get_t(int Left,int Right)  
 36 {  
 37     for(int i=1;i<=lent;i++)  
 38     {  
 39         tt[i]+=t[i]*Left;  
 40         tt[i+1]+=tt[i]/10;  
 41         tt[i]%=10;  
 42     }  
 43     lent++;  
 44     while(tt[lent]>=10)  
 45     {  
 46         tt[lent+1]=tt[lent]/10;  
 47         tt[lent]%=10;  
 48         lent++;  
 49     }  
 50     while(lent>1&&tt[lent]==0) lent--;  
 51     len=lent;  
 52     memcpy(t,tt,sizeof(tt));  
 53     memset(tt,0,sizeof(tt));  
 54     for(int i=1,j=len;i<=len;i++,j--)  
 55         t2[i]=t[j];  
 56     int x=0,y=0;  
 57     for(int i=1;i<=len;i++)  
 58     {  
 59         y=x*10+t2[i];  
 60         tt[i]=y/Right;  
 61         x=y%Right;  
 62     }  
 63     x=1;  
 64     while(x<len&&tt[x]==0) x++;  
 65     memset(t2,0,sizeof(t2));  
 66     for(int i=1,j=x;j<=len;i++,j++)  
 67         t2[i]=tt[j];  
 68     memcpy(tt,t2,sizeof(t2));  
 69     len=len+1-x;  
 70 }  
 71 bool _cmp()  
 72 {  
 73     if(len>lena) return true;  
 74     if(len<lena) return false;  
 75     for(int i=1;i<=len;i++)  
 76     {  
 77         if(ans[i]<tt[i]) return true;  
 78         if(ans[i]>tt[i]) return false;  
 79     }  
 80     return false;  
 81 }   
 82 void _solve()  
 83 {  
 84     _qst_ab(1,N);  
 85     t[1]=1;lent=1;  
 86     for(int i=1;i<=N;i++)  
 87     {  
 88         memset(tt,0,sizeof(tt));  
 89         len=0;  
 90         _get_t(a[i-1],b[i]);  
 91         if(_cmp())  
 92         {  
 93             memcpy(ans,tt,sizeof(tt));  
 94             lena=len;  
 95         }  
 96     }  
 97     for(int i=1;i<=lena;i++)  
 98         printf("%d",ans[i]);  
 99     printf("\n");  
100 }  
101 int main()  
102 {  
103     _init();  
104     _solve();  
105     return 0;  
106 }  

 

以上是关于[Daimayuan]新国王游戏(C++,数学)的主要内容,如果未能解决你的问题,请参考以下文章

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

国王的麦子,老题目,c语言(dev-c++),要高精度,输入第n格,输出那一格麦子数

C++国王买瓷器(模拟)

[Daimayuan]数组操作(C++,字符串)

CodeVS 1198NOIP 2012国王游戏

开源 C++ 游戏引擎数学库?