白告山风

不定期更新摄影,acm题解等等有趣的东西~

0%

P8482 Number 贪心 高精度 情况模拟

题目链接


思路:

刚开始看到这道题的时候,思路就有点乱,首先当然是如何选出数字组成使得两个数乘积最大。凭着感觉我一开始写了一个将数字从小到大分配,并且实时判断当前的数字谁小,谁小下一个数字就放谁那。当然这个思路有问题,首先我们知道大的数字一定在高位,所以我们要把大的数字尽可能放在前面,如此一来每个数字就只有两个相同位的不同选择,此时两数和已经固定了,按照数字知识可知,两数差越小,积越大。我们在回首我们分配数字的时候的规律,假如我们你一个我一个这样分,先被分到的a永远大于等于后被分到的b。所以我们要对一个数组,前面取最大,后面取最小,这样这个数组与另一个数组的差就会最小。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
#include<stdio.h>
const int N=1e7+3;
int a[10],a1[N],b1[N],remain[N];
void Reversal(int *arr){//翻转,这个里用全局变量对大小要求一点。

for(int i=1;i<=arr[0];i++){
remain[i]=arr[arr[0]-i+1];
}
for(int i=1;i<=arr[0];i++){
arr[i]=remain[i];
}
}
void mult(int *arr){
int remain=0;
for(int i=1;i<=arr[0];i++){
arr[i]=arr[i]*2+remain;
remain=arr[i]/10;
arr[i]%=10;
}
while(remain){
arr[++arr[0]]=remain%10;
remain/=10;
}
for(int i=arr[0];i>0;i--){
printf("%d",arr[i]);
}
printf("\n");
}
void chu(int *arr){
int arr1=0;
for(int i=1;i<=arr[0];i++){
arr1=arr1*10+arr[i];
arr[i]=0;//!!注意这里的归零,默认当前位除不了,归零
if(arr1>=2){
arr[i]=arr1/2;
arr1%=2;
}
}
int flag=1;
for(int i=1;i<=arr[0];i++){
if(flag&&arr[i]==0)continue;
flag=0;
printf("%d",arr[i]);
}
printf("\n");
}
int main(){
for(int i=0;i<10;i++){
scanf("%d",&a[i]);
}
int flag=1,flag1=1;
for(int i=9;i>=0;){
while(a[i]){
a[i]--;
if(flag)a1[++a1[0]]=i;
else b1[++b1[0]]=i;
flag=!flag;
}
i--;
if(flag1){
if(flag==0){//!!注意这里当且仅当出现大小差异且下一步准备放在小一点的数组时启动,这样可以保证数组-(大-小)-(小-大)这样差最小。
flag1=0;
a[i]--;
b1[++b1[0]]=i;
}
}
}
if(a1[a1[0]]==0){
Reversal(b1);
chu(a1);
mult(b1);
}
else{
Reversal(a1);
chu(b1);
mult(a1);
}
return 0;
}