1 条题解
-
0
数学题?观察到性质还挺好写的。
分析
首先认真审题,题目说的是包含一个由 个十进制数位组成的整数 ,所以最大是十万位,用 int 或者 long long 存储显然是不现实的,所以用高精度存储答案和 int128 在中间运算。
接下来就是思路处理了:
题目只要求找到
因为这道题的 ()。
我们不妨从一个数字移动的位数考虑,找到一个移动位数可以让交换产生的价值完全覆盖代价。 不妨假想一种极限情况,现在有一串数字 , 是第十七位, 是第一位,将 交换到第十七位本身能带来 的价值。
现在如果交换一次的花销是 ,因为我们进行了 次交换,所以总贡献是负数。接下来就是找到一个让这个代价能被覆盖的位置,可以找到:
$2199999999999999999 - 1999999999999999992 - 18 \times 10^{16} = 20000000000000007$。
此时 在第十九位,这就是我们要找的位数。也就是说:当一个数字移动到了第十九位之前(包括十九),一定可以为我带来正价值。
扩展来说:第十九位之前的从大到小排序,一定可以为我带来正价值更进一步的讲,我们可以将整个字符串先整体从大到小排序,然后将十九位之后的按照原本的相对顺序排序,最后针对后十八位暴力就可以了。
当然你不放心可以枚举后面二十位,我代码也是按照二十写的。
暴力算的方式因人而异,这里提供我教练上课教的。实现
#include<bits/stdc++.h> using namespace std; #define int __int128 inline int read(){ int x=0,f=1; char ch=getchar(); while(ch<'0'||ch>'9'){ if(ch=='-')f=-1; ch=getchar(); } while(ch>='0'&&ch<='9'){ x=x*10+ch-48; ch=getchar(); } return x*f; } void write(int x){ if(x<0){ putchar('-'); x=-x; } if(x>9){ write(x/10); } putchar(x%10+'0'); } const int N=1e5+5; struct Node{ int v,id; bool operator < (const Node &rhs)const{ return id<rhs.id; } }a[N]; bool cmp(const Node &a,const Node &b){ if(a.v==b.v)return a.id<b.id; return a.v>b.v; } string x; int y,ans[N],p[N],cnt,ans1[N],maxn,mcur; signed main(){ cin>>x; y=read(); int len=x.size(); int l=max(len-20,(int)1); x=' '+x; for(int i=1;i<=len;i++){ ans[i]=x[i]-'0';//转化成数字,方便计算 a[i].v=ans[i]; a[i].id=i;//后面排序用 } if(len>20){ sort(a+1,a+len+1,cmp);//整体排序 sort(a+len-20+1,a+len+1);//按原相对顺序排列后20位 } for(int i=1;i<=len;i++){ ans[i]=a[i].v; } for(int i=l;i<=len;i++){ p[i]=ans[i];//这里记录原本后面20位的顺序,暴力枚举的时候初始化用 } for(int k=0;k<=20*20+5;k++){ int curk=k,cur=0; for(int i=l;i<=len;i++){ ans[i]=p[i]; } for(int i=l;i<=len;i++){ cnt=0; for(int j=i;j<=len;j++){ if(ans[j]>ans[cnt]&&curk>=j-i){ cnt=j; } } if(cnt){ curk=curk-cnt+i; } for(int j=cnt;j>i;j--){ swap(ans[j],ans[j-1]); } } for(int i=l;i<=len;i++){ cur=cur*10+ans[i]; } if((cur-k*y>maxn)||(cur-k*y==maxn&&cur>mcur)){//当前情况更优,更新我的答案 maxn=cur-k*y; mcur=cur; for(int i=l;i<=len;i++){ ans1[i]=ans[i];//ans1存储的是后20位的顺序 } } } //二十位之前在ans中,后面的在ans1,输出即可 for(int i=1;i<l;i++){ write(ans[i]); } for(int i=l;i<=len;i++){ write(ans1[i]); } return 0; }
- 1
信息
- ID
- 7142
- 时间
- 1000ms
- 内存
- 512MiB
- 难度
- 10
- 标签
- 递交数
- 2
- 已通过
- 1
- 上传者