P1080 [NOIP2012 提高组] 国王游戏
written on 2022-05-22
所以我好不容易打了一大摞数学公式这题却交不了了??
第一道较为正式的贪心题吧。
思路历程:
-
这道题前40%的点都可以状压乱水,后面的点比较大,本来尝试用一些不一样的 dp ,但是乘积也极大,状态根本记不下,于是放弃 dp。
-
题目求问最大值最小,一下可以想到二分,但是对于判定却不能做到合理的时间复杂度分配,于是这个做法又寄了。
-
几种方法都不行,于是考虑贪心。贪心的典型套路是看相邻的两项能否交换。对于这道题,我们来具体分析一下:
考虑序列中的两项
-
若
在 前,此时 -
若
在 前,此时
为方便起见,下面将
比较两种情况,容易发现有
于是按照这样的顺序排序,然后顺序扫一遍找最大值即可在
注意还要写高精!
贪心代码
#include<bits/stdc++.h>
#define N 1005
using namespace std;
typedef long long ll;
int n;
struct F
{
ll x,y,s;
}a[N];
bool cmp(F a,F b){return a.s<b.s;}
int now[10005],t[10005],ans[10005];
int Ans,len,lent;
bool check()
{
if(Ans>lent) return 0;
if(Ans<lent) return 1;
for(int i=1;i<=lent;i++)
{
if(ans[i]<t[i]) return 1;
if(ans[i]>t[i]) return 0;
}
return 0;
}
void update()
{
Ans=lent;
for(int i=1;i<=Ans;i++) ans[i]=t[i];
}
void divide(ll x)
{
int jw=0;
for(int i=1;i<=len;i++)
{
t[i]=(jw*10+now[i])/x;
jw=(jw*10+now[i])%x;
}
int p=-1;
for(int i=1;i<=len;i++)
if(t[i]){p=i;break;}
if(p==-1) lent=0;
else lent=len-p+1;
if(p==-1) return ;
for(int i=1;i<=lent;i++) t[i]=t[p+i-1];
//divide
}
void times(ll x)
{
int jw=0;
for(int i=1;i<=len;i++) now[i]*=x;
for(int i=len;i;i--)
{
x=now[i]+jw;
jw=x/10;
now[i]=x%10;
}
lent=0;
while(jw)
{
t[++lent]=jw%10;
jw/=10;
}
for(int i=len+lent;i>=lent+1;i--) now[i]=now[i-lent];
for(int i=1;i<=lent;i++) now[i]=t[lent-i+1];
len+=lent;
}
void work()
{
sort(a+1,a+1+n,cmp);
// now=a[0].x;
ll x=a[0].x;
while(x)
{
t[++len]=x%10;
x/=10;
}
for(int i=1;i<=len;i++) now[i]=t[len-i+1];
for(int i=1;i<=n;i++)
{
// ans=max(ans,now/a[i].y);
divide(a[i].y);
if(check()) update();
// times(now,a[i].x);
// now*=a[i].x;
times(a[i].x);
}
for(int i=1;i<=Ans;i++) printf("%d",ans[i]);
}
int main()
{
scanf("%d",&n);
for(int i=0;i<=n;i++)
{
scanf("%lld%lld",&a[i].x,&a[i].y);
a[i].s=a[i].x*a[i].y;
}
work();
}
附40分代码(状压dp)
#include<bits/stdc++.h>
#define N 1005
using namespace std;
typedef long long ll;
int n;
ll ans;
struct F{ll x,y;}a[N];
ll f[(1<<20)+5],val[(1<<20)+5];
void work()
{
f[0]=0;
for(int i=0;i<(1<<n);i++)
{
val[i]=a[0].x;
if(i) f[i]=1e18;
for(int j=0;j<n;j++)
{
if(!(i&(1<<j))) continue;
f[i]=min(f[i],max(f[i^(1<<j)],val[i^(1<<j)]/a[j+1].y));
val[i]*=a[j+1].x;
}
}
printf("%lld\n",f[(1<<n)-1]);
}
int main()
{
scanf("%d",&n);
for(int i=0;i<=n;i++) scanf("%lld%lld",&a[i].x,&a[i].y);
work();
}
update on 2022-7-31
注意这题的贪心分析策略——邻项分析法,这在贪心题的分析中是很重要的。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!