hdu 7106 Function
题意:
- 让求这个函数的最小值( x ∈ [ 1 , n ] x \in[1,n] x∈[1,n] )
分析:
-
若直接枚举 x x x 会超时,转换思路:去枚举 g [ x ] g[x] g[x] , g [ x ] g[x] g[x] 最大才 54 54 54
-
先 将 式 子 化 简 一 下 : f = ( A ∗ g [ x ] + b ) x 2 + ( C ∗ g [ x ] 2 + D ∗ g [ x ] ) x 先将式子化简一下:f=(A*g[x]+b)x^2+(C*g[x]^2+D*g[x])x 先将式子化简一下:f=(A∗g[x]+b)x2+(C∗g[x]2+D∗g[x])x
-
先预处理打表,将每个对应 g [ x ] g[x] g[x] 的 i i i p u s h push push 到 v e c t o r vector vector 里
然后再遍历枚举 g [ x ] g[x] g[x] ,根据函数的对称轴求函数极值即可
可以采用二分(要分类讨论),三分不需要
二分的三种情况我想不清楚为什么不能合并
二分:
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=1e6+5;
vector <int> g[66];
int fa[N];
ll cal(ll m,ll n,ll x) { return m*x*x+n*x; }
signed main()
{
for (int i=1;i<=1e6;i++)
{
fa[i]=fa[i/10]+i%10;
g[fa[i]].push_back(i);
}
int T;
scanf("%d",&T);
while(T--)
{
int a,b,c,d,p;
scanf("%d%d%d%d%d",&a,&b,&c,&d,&p);
ll ans=1e18;
for(int i=1;i<=54;i++)
{
if(g[i][0]>p) break;
ll m=1ll*a*i+b, n=1ll*c*i*i+d*i, h=0;
int l=0, r=upper_bound(g[i].begin(),g[i].end(),p)-g[i].begin()-1;
if(m<=0)
{
ans=min({ans,cal(m,n,g[i][0]),cal(m,n,g[i][r])});
continue;
}
h=n/(-2*m);
if(h<g[i][0]) ans=min(ans,cal(m,n,g[i][0])); // 这里不能取<=,因为h本是小数,取整会变小
else if(h>=g[i][r]) ans=min(ans,cal(m,n,g[i][r]));
// 我觉得这两种特殊情况可以合并到第三种,只需要把for里面r再判断一下有无越界即可
// 交到杭电就一直wa,想不明白
else
{
r=upper_bound(g[i].begin(),g[i].end(),h)-g[i].begin()-1;
for(int j=r;j<=r+1;j++) ans=min(ans,cal(m,n,g[i][j]));
}
}
printf("%lld\n",ans);
}
return 0;
}
三分:
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=1e6+5;
vector <int> g[66];
int fa[N];
ll cal(ll m,ll n,ll x) { return m*x*x+n*x; }
signed main()
{
for (int i=1;i<=1e6;i++)
{
fa[i]=fa[i/10]+i%10;
g[fa[i]].push_back(i);
}
int T;
scanf("%d",&T);
while(T--)
{
int a,b,c,d,p;
scanf("%d%d%d%d%d",&a,&b,&c,&d,&p);
ll ans=1e18;
for(int i=1;i<=54;i++)
{
if(g[i][0]>p) break;
ll m=1ll*a*i+b, n=1ll*c*i*i+d*i, h=0;
int l=0, r=upper_bound(g[i].begin(),g[i].end(),p)-g[i].begin()-1;
if(m<=0)
{
ans=min({ans,cal(m,n,g[i][0]),cal(m,n,g[i][r])});
}
else
{
while(l+5<r)
{
int lmd=l+(r-l)/3, rmd=r-(r-l)/3;
if(cal(m,n,g[i][lmd])<=cal(m,n,g[i][rmd])) r=rmd;
else l=lmd;
}
for(int j=l;j<=r;j++) ans=min(ans,cal(m,n,g[i][j]));
}
}
printf("%lld\n",ans);
}
return 0;
}