Codeforces Round 961 (Div. 2) A~C

封面原图链接 画师Miv4t

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=mk1a 再对稍微贵一点的花做同样的操作 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=lftk2b 现在考虑把一些便宜的换成贵的使得花出去的钱还能一个一个增加 不难发现最多可以转移 r = m i n ( k 1 , d − k 2 , l f t ) r = min(k1, d - k2, lft) r=min(k1,dk2,lft)次 那么最终花出去的钱就是 n o w = ( k 1 − r ) ∗ a + ( k 2 + r ) ∗ b now = (k1 - r) * a + (k2 + r) * b now=(k1r)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[i1] 然后直接写代码实现即可

代码

#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;
}
  • 13
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值