Educational Codeforces Round 98 (Rated for Div. 2)

比赛链接 https://codeforces.com/contest/1452
比赛记录 https://blog.csdn.net/cheng__yu_/article/details/105395197

B. Toy Blocks (二分)

链接:https://codeforces.com/contest/1452/problem/B

题意:有 n 个盒子,每个盒子有 a_i 个糖果。现在你可以向一些盒子中添加糖果,使得任选一个盒子,将其中的糖果分到其余 n-1 个盒子中,每个盒子的糖果数量相等。问最少需要添加多少糖果。 ( 1 ≤ n ≤ 1 0 5 , 0 ≤ a i ≤ 1 0 9 ) (1\le n \le 10^5,0\le a_i\le 10^9) (1n105,0ai109)

思路:一般来说答案就是最大的高度。然后补成 n − 1 n-1 n1 的倍数就好了。也就不用二分了。

#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int maxn=1e5+5;
ll t,n;
ll a[maxn];
ll ans,sum;
bool check(ll mid)
{
    ll tot=mid*(n-1);
    return tot>=sum;
}
int main()
{
    scanf("%lld",&t);
    while(t--)
    {
        scanf("%lld",&n);
        ll L=0,R=2e9;
        sum=0;
        for(int i=1; i<=n; ++i) scanf("%lld",&a[i]),L=max(L,a[i]),sum+=a[i];
        while(L<R)
        {
            ll mid=(L+R)>>1;
            if(check(mid)) R=mid;
            else L=mid+1;
        }
        ans=L*(n-1)-sum;
        printf("%lld\n",ans);
    }
    return 0;
}

D. Radio Towers (线性DP)

在这里插入图片描述
链接:https://codeforces.com/contest/1452/problem/D

题意:在区间 [ 0 , n + 1 ] [0,n+1] [0,n+1] 上设置灯塔。假设灯塔在 x i x_i xi ,照射半径为 r i r_i ri,那么就会照射 [ x i − r i , x i + r i ] [x_i-r_i,x_i+r_i] [xiri,xi+ri] 范围内的点。要求 0 0 0 n + 1 n+1 n+1 不被照射。 [ 1 , n ] [1,n] [1,n] 每个点仅被照射一次。其中 [ 1 , n ] [1,n] [1,n] 每个点设置灯塔的概率为 1 2 \frac 12 21 ,问符合条件的概率是多少。 ( 1 ≤ n ≤ 2 × 1 0 5 ) (1\le n \le 2\times 10^5) (1n2×105)

思路:设 dp[i] 表示 [1,i] 符合条件的方案数。

  • d p [ i ] = d p [ i − 1 ] + d p [ i − 3 ] + d p [ i − 5 ] + … dp[i]=dp[i-1]+dp[i-3]+dp[i-5]+\dots dp[i]=dp[i1]+dp[i3]+dp[i5]+
  • 因此由上式可得: d p [ i ] = d p [ i − 1 ] + d p [ i − 2 ] dp[i]=dp[i-1]+dp[i-2] dp[i]=dp[i1]+dp[i2]
#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int maxn=2e5+5,N=2e5,mod=998244353;
int n,dp[maxn];
int qpow(int b,int n,int mod)
{
    int res=1;
    while(n)
    {
        if(n&1) res=1ll*res*b%mod;
        b=1ll*b*b%mod;
        n>>=1;
    }
    return res;
}
int main()
{
    dp[0]=0,dp[1]=1;
    for(int i=2; i<=N; ++i) dp[i]=(1ll*dp[i-1]+dp[i-2])%mod;
    cin>>n;
    int inv2=qpow(2,n,mod);
    inv2=qpow(inv2,mod-2,mod);
    cout<<1ll*dp[n]*inv2%mod<<"\n";
    return 0;
}

E. Two Editorials (二次差分)

链接:https://codeforces.com/contest/1452/problem/E

题意:在区间 [1,n] 上有 m 个区间,你可以选择在 [1,n] 上选择两个长度为 k 的区间染色。上述的 m 个区间,只能取两个染色区间的其中一个计算染色的数量。问 m 个区间最多能够染色的长度是多少? ( 1 ≤ n , m ≤ 2000 , 1 ≤ k ≤ n , 1 ≤ l i ≤ r i ≤ n ) (1\le n,m\le 2000,1\le k \le n, 1\le l_i \le r_i\le n) (1n,m2000,1kn,1lirin)

思路

  • 直接暴力的想,枚举两个染色区间的右端点,然后遍历 m 个区间,统计答案。时间复杂度 O ( n 2 m ) O(n^2m) O(n2m)
  • 正确的做法是:先枚举第一个区间。统计出 m 个区间在第一个区间的贡献 a i a_i ai ,然后再统计第二个区间对 a i a_i ai 的贡献。可以这样想,第二个区间的右端点,从 k 开始一步一步往 n 移动。这其中,每次移动时,对一个特定的 a i a_i ai 产生的贡献也会发生变化。贡献首先会不断 + 1 ,然后是一段 0 ,最后是 -1 ,再是 0 。因此可以用两次差分来完成。
#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int maxn=2010;

int n,m,k;
int l[maxn],r[maxn],a[maxn];
int cnt[maxn*10];

int main()
{
    scanf("%d%d%d",&n,&m,&k);
    for(int i=1; i<=m; ++i) scanf("%d%d",&l[i],&r[i]);
    int ans=0;
    for(int i=1; i+k-1<=n; ++i)
    {
        int res=0;
        for(int j=1; j<=m; ++j)
        {
            a[j]=max(0,min(i+k-1,r[j])-max(i,l[j])+1);
            res+=a[j];
        }
        memset(cnt,0,sizeof(cnt));
        for(int j=1; j<=m; ++j)
        {
            int len=r[j]-l[j]+1;
            if(k<=len)
            {
                cnt[l[j]+a[j]]++;
                cnt[l[j]+k]--;
                cnt[r[j]+1]--;
                cnt[r[j]-a[j]+1+k]++;
            }
            else
            {
                cnt[l[j]+a[j]]++;
                cnt[r[j]+1]--;
                cnt[l[j]+k]--;
                cnt[r[j]-a[j]+1+k]++;
            }
        }
        int tmp=0;
        for(int i=1; i<=n; ++i) cnt[i]+=cnt[i-1];
        for(int i=1; i<=n; ++i) cnt[i]+=cnt[i-1],tmp=max(tmp,cnt[i]);
        ans=max(ans,res+tmp);
    }
    printf("%d\n",ans);
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值