A - 对角线
题意
给一个n*n的范围 要填入k个棋子 要求使得有棋子的对角线最少
思路
考虑贪心 我们按顺序填 先填中间最长的对角线 填满之后再填那两边稍微短一点的对角线 不难发现对角线长度分别是n,n-1,n-1,n-2,n-2,······,1,1 所以直接循环把k减到1为止即可
代码
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef double db;
typedef pair<int,int> pii;
typedef pair<ll,ll> pll;
void solve()
{
int n,k;
scanf("%d%d",&n,&k);
int now=n;
int lst=0;
int cnt=0;
while(k>0)
{
k-=now;
cnt++;
if(lst==0)
{
lst=now;
now--;
continue;
}
if(now==lst)
now--;
else
lst=now;
}
printf("%d\n",cnt);
}
int main()
{
int T=1;
scanf("%d",&T);
while(T--)
{
solve();
}
return 0;
}
B - 花束
题意
总钱数有限 不同价格的花也有限 要求最多只能买价格相差1的两种花 问最多能花出去多少钱
思路
先排序然后遍历查找 当遇到有相差1的两种花就需要考虑分别选多少个才能最大化花出去的钱了
我们不妨假设这两种花的价格分别是a和b 个数是c和d 我们可以先优先尝试把a尽可能多放一点 对于现在的m a最多能放的也就是
⌊
m
a
⌋
\left\lfloor\frac{m}{a}\right\rfloor
⌊am⌋束 所以实际上我买的花的数量应该是
k
1
=
m
i
n
(
c
,
⌊
m
a
⌋
)
k1 = min(c, \left\lfloor\frac{m}{a}\right\rfloor)
k1=min(c,⌊am⌋) 现在剩下的钱就是
l
f
t
=
m
−
k
1
∗
a
lft = m - k1 * a
lft=m−k1∗a 再对稍微贵一点的花做同样的操作
k
2
=
m
i
n
(
d
,
⌊
l
f
t
b
⌋
)
k2 = min(d, \left\lfloor\frac{lft}{b}\right\rfloor)
k2=min(d,⌊blft⌋) 更新剩下的钱为
l
f
t
=
l
f
t
−
k
2
∗
b
lft = lft - k2 * b
lft=lft−k2∗b 现在考虑把一些便宜的换成贵的使得花出去的钱还能一个一个增加 不难发现最多可以转移
r
=
m
i
n
(
k
1
,
d
−
k
2
,
l
f
t
)
r = min(k1, d - k2, lft)
r=min(k1,d−k2,lft)次 那么最终花出去的钱就是
n
o
w
=
(
k
1
−
r
)
∗
a
+
(
k
2
+
r
)
∗
b
now = (k1 - r) * a + (k2 + r) * b
now=(k1−r)∗a+(k2+r)∗b 遍历的过程当中更新就行
代码
B1
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef double db;
typedef pair<int,int> pii;
typedef pair<ll,ll> pll;
const int N=200010;
ll n,m;
pll a[N];
ll tmp[N];
void solve()
{
scanf("%lld%lld",&n,&m);
for(int i=1;i<=n;i++) scanf("%lld",&tmp[i]);
sort(tmp+1,tmp+n+1);
int j=1;
for(int i=1;i<=n;i++)
{
if(i==1 or tmp[i]!=tmp[i-1])
{
a[j].first=tmp[i];
a[j].second=1;
j++;
}
else
{
a[j-1].second++;
}
}
ll ans=0;
for(int i=1;i<j-1;i++)
{
if(a[i].first+1==a[i+1].first)
{
ll max_flowers1=m/a[i].first;
ll ned1=min(max_flowers1,a[i].second);
ll lft1=m-a[i].first*ned1;
ll max_flowers2=lft1/a[i+1].first;
ll ned2=min(max_flowers2,a[i+1].second);
ll lft2=lft1-a[i+1].first*ned2;
ll change=min(ned1,min(a[i+1].second-ned2,lft2));
ans=max(ans,(ned1-change)*a[i].first+(ned2+change)*a[i+1].first);
}
else
{
ll take=min(m/a[i].first,a[i].second);
ans=max(ans,take*a[i].first);
}
}
ll take=min(m/a[j-1].first,a[j-1].second);
ans=max(ans,take*a[j-1].first);
printf("%lld\n",ans);
}
int main()
{
int T=1;
scanf("%d",&T);
while(T--)
{
solve();
}
return 0;
}
B2
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef double db;
typedef pair<int,int> pii;
typedef pair<ll,ll> pll;
const int N=200010;
ll n,m;
pll a[N];
void solve()
{
scanf("%lld%lld",&n,&m);
for(int i=1;i<=n;i++) scanf("%lld",&a[i].first);
for(int i=1;i<=n;i++) scanf("%lld",&a[i].second);
sort(a+1,a+n+1);
ll ans=0;
for(int i=1;i<n;i++)
{
if(a[i].first+1==a[i+1].first)
{
ll max_flowers1=m/a[i].first;
ll ned1=min(max_flowers1,a[i].second);
ll lft1=m-a[i].first*ned1;
ll max_flowers2=lft1/a[i+1].first;
ll ned2=min(max_flowers2,a[i+1].second);
ll lft2=lft1-a[i+1].first*ned2;
ll change=min(ned1,min(a[i+1].second-ned2,lft2));
ans=max(ans,(ned1-change)*a[i].first+(ned2+change)*a[i+1].first);
}
else
{
ll take=min(m/a[i].first,a[i].second);
ans=max(ans,take*a[i].first);
}
}
ll take=min(m/a[n].first,a[n].second);
ans=max(ans,take*a[n].first);
printf("%lld\n",ans);
}
int main()
{
int T=1;
scanf("%d",&T);
while(T--)
{
solve();
}
return 0;
}
C - 平方
题意
给定一个序列 每次操作可以使任意一个数变成自己的平方 问最小进行多少次操作可以变成一个不严格递增的序列
思路
n的范围很小 所以不难想到直接模拟即可 但是遇到的主要问题就是前面的数多次平方可能会特别大 数字还会越滚越大 那么势必会把long long的范围爆掉 自然地可以想到尝试用Python去解决
def solve():
n=int(input())
a=list(map(int,input().split()))
cnt=0
for i in range(1,n):
if a[i]<a[i-1]:
if a[i]==1:
print(-1)
return
while a[i]<a[i-1] :
a[i]=a[i]*a[i]
cnt+=1
print(cnt)
T=int(input())
for _ in range(T):
solve()
结果TLE3了 也就是说我们还需要一个
O
(
1
)
O(1)
O(1)的算法来解决每次加多少的问题 于是我们想到了对数运算
不妨在开始的时候就将所有数取一个对数 这样就可以有效地减小数据范围 每次的平方操作也转移成了*2的操作 但是发现
2
1000
2^{1000}
21000还是会把long double爆掉 我们还可以再多取一次对数 那么每个数需要操作的次数仍然可以推导出来
⌈
b
[
i
]
−
b
[
i
−
1
]
log
(
2
)
⌉
\displaystyle{\left\lceil\frac{b[i] - b[i - 1]}{\log(2)}\right\rceil}
⌈log(2)b[i]−b[i−1]⌉ 然后直接写代码实现即可
代码
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef double db;
typedef long double ld;
typedef pair<int,int> pii;
typedef pair<ll,ll> pll;
void solve()
{
int n;
scanf("%d",&n);
vector<ld> a(n);
for(int i=0;i<n;i++) scanf("%Lf",&a[i]);
for(int i=1;i<n;i++)
{
if(a[i]<a[i-1] and (int)a[i]==1)
{
printf("-1\n");
return ;
}
}
for(int i=0;i<n;i++) a[i]=log(log(a[i]));
ll ans=0;
for(int i=1;i<n;i++)
{
ld ned=a[i-1]-a[i];
if(ned>1e-9)
{
int cnt=1+(ned-1e-9)/log(2);
ans+=cnt;
a[i]+=cnt*log(2);
}
}
printf("%lld\n",ans);
}
int main()
{
int T=1;
scanf("%d",&T);
while(T--)
{
solve();
}
return 0;
}