Educational Codeforces Round 66 (Rated for Div. 2) Jun/05/2019 22:35UTC+8

Educational Codeforces Round 66 Rated for Div. 2 Jun/05/2019 22:35UTC+8

    • B. Catch Overflow! (模拟栈操作)
    • C. Electrification (绝对值 + 思维)*
    • D. Array Splitting (前缀和)
    • E. Minimal Segment Cover(倍增)
    • F. The Number of Subpermutations(思维 + rmq || 分治)

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

B. Catch Overflow! (模拟栈操作)

Educational Codeforces Round 66 (Rated for Div. 2) Jun/05/2019 22:35UTC+8_第1张图片

#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int maxn=1e5+10;
const ll lim=(1ll<<32)-1;

int q;
ll s[maxn],top;

int main()
{
    ll ans=0;
    ll times=1;
    s[0]=1;
    cin>>q;
    while(q--)
    {
        string op;
        cin>>op;

        if(op[0]=='a')
        {
            ans+=s[top];
            if(ans>lim)
            {
                puts("OVERFLOW!!!");
                return 0;
            }
        }
        else if(op[0]=='f')
        {
            int x;
            cin>>x;
            s[++top]=min(s[top-1]*x,lim+1);
        }
        else if(op[0]=='e')
            top--;
    }
    cout<<ans<<"\n";
    return 0;
}

C. Electrification (绝对值 + 思维)*

Educational Codeforces Round 66 (Rated for Div. 2) Jun/05/2019 22:35UTC+8_第2张图片
题意:给定一个数组 a ,找到一个 x 使得第 k + 1个 x与 a i a_i ai的绝对值最小
思路:找到距离最近的 k+1个数即可

#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int maxn=2e5+10;
const ll lim=(1ll<<32)-1;


int t,n,k;
int a[maxn];

int main()
{
    cin>>t;
    while(t--)
    {
        cin>>n>>k;
        for(int i=1;i<=n;++i) cin>>a[i];
        ll dis=9e18,ans;
        for(int i=1;i+k<=n;++i)
        {
            if(dis>a[i+k]-a[i])
            {
                dis=a[i+k]-a[i];
                ans=(a[i+k]+a[i])/2;
            }
        }
        cout<<ans<<"\n";
    }
    return 0;
}

D. Array Splitting (前缀和)

Educational Codeforces Round 66 (Rated for Div. 2) Jun/05/2019 22:35UTC+8_第3张图片
题意: 给定长度为 n 个数组,划分成 k 个非空子集,要求 ∑ i = 1 n a i × f ( i ) \sum_{i=1}^n a_i\times f(i) i=1nai×f(i)最大。f(i)表示第 i 个元素在第 f(i)个子集

思路: 在 n -1 个前缀中删去最小的 k -1 个前缀。

#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int maxn=3e5+10;
const ll lim=(1ll<<32)-1;
int n,k;
int a[maxn];
ll pref[maxn];

int main()
{
    ll sum=0;
    cin>>n>>k;
    for(int i=1;i<=n;++i) cin>>a[i];
    for(int i=1;i<=n;++i)
    {
        pref[i]=pref[i-1]+a[i];
        sum+=a[i];
    }

    sort(pref+1,pref+n);
    ll ans=sum*k;

    for(int i=1;i<=k-1;++i)
    {
        ans-=pref[i];
    }
    cout<<ans<<"\n";
    return 0;
}

E. Minimal Segment Cover(倍增)

Educational Codeforces Round 66 (Rated for Div. 2) Jun/05/2019 22:35UTC+8_第4张图片
题意:给定 n 条线段,给出 m 个区间的询问,问最少需要多少条线段可以覆盖当前询问的区间。 ( n , m ≤ 2 e 5 , l i , r i ≤ 5 e 5 ) (n,m\le 2e5 , l_i,r_i\le 5e5) (n,m2e5,li,ri5e5)

思路

  • d p [ i ] [ j ] dp[i][j] dp[i][j] 表示当前位置 i 通过 2 j 2^j 2j 条线段能够到达的最远距离
  • 预处理出,当前位置 i 通过 1条线段能够到达的最远距离,通过2条线段能够到达的最远距离,通过4条线段能够到达的最远距离。
#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int maxn=5e5;

int n,m,maxr;
int dp[maxn+10][25];

int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;++i)
    {
        int l,r;
        scanf("%d%d",&l,&r);
        dp[l][0]=max(dp[l][0],r);
        maxr=max(maxr,r);
    }
    for(int l=1;l<=maxr;++l)
        dp[l][0]=max(dp[l][0],max(l,dp[l-1][0]));
    for(int j=1;j<=20;++j)
        for(int i=0;i<=maxr;++i)
            dp[i][j]=dp[dp[i][j-1]][j-1];
    while(m--)
    {
        int l,r;
        ll ans=0;
        scanf("%d%d",&l,&r);
        if(r>maxr||dp[l][20]<r)
        {
            puts("-1");
            continue;
        }
        for(int i=20;i>=0;--i)
            if(dp[l][i]<r)
                l=dp[l][i],ans+=(1<<i);
        ans++;
        printf("%lld\n",ans);
    }
    return 0;
}

F. The Number of Subpermutations(思维 + rmq || 分治)

Educational Codeforces Round 66 (Rated for Div. 2) Jun/05/2019 22:35UTC+8_第5张图片
题意:给以一个长度为 n 的数组,求区间 [ l , r ] [l,r] [l,r] 是排列的个数
思路

  • 排列需要满足,区间长度等于最大值,且每个数只出现一次。
  • 因此处理出每个点 i 向右最多的不同的数字个数。然后就可以枚举每个点,在 i 和 r[i]中找可能的答案

实现

  • 从 n 到 1,记录每个点 i 上次出现的位置,与点 i + 1 取个min
  • 用 rmq 处理一下最大值的查询
#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int maxn=3e5+10;

int n;
int a[maxn],last[maxn];
int dp[maxn][20],r[maxn];

void init()
{
    for(int i=1;i<=n;++i) dp[i][0]=a[i];
    for(int j=1;(1<<j)<=n;++j)
        for(int i=1;i+(1<<j)-1<=n;++i)
            dp[i][j]=max(dp[i][j-1],dp[i+(1<<j-1)][j-1]);
}

int queryMax(int l,int r)
{
    int k=log2(r-l+1);
    return max(dp[l][k],dp[r-(1<<k)+1][k]);
}

int main()
{
    scanf("%d",&n);
    for(int i=1;i<=n;++i) scanf("%d",&a[i]);
    r[n+1]=n;
    for(int i=n;i>=1;--i)
    {
        if(last[a[i]]) r[i]=min(r[i+1],last[a[i]]-1);
        else r[i]=r[i+1];
        last[a[i]]=i;
    }
    init();
    int ans=0;
    for(int i=1;i<=n;++i)
    {
        int j=i;
        while(j<=r[i])
        {
            if(queryMax(i,j)==j-i+1) ans++,j++;
            else j=i+queryMax(i,j)-1;
        }
    }
    printf("%d\n",ans);
    return 0;
}

学长的分治代码

#include <bits/stdc++.h>
using namespace std;
#define MAXNUM 333333
#define rep(i,s,t) for(int i=s;i<t;i++)
#define pii pair<int,int>
int per[MAXNUM],pos[MAXNUM],f[20][MAXNUM],LOG[MAXNUM],n;
pii fnum[20][MAXNUM],num[MAXNUM];
void getlist()
{
    LOG[0] = -1;
    for (int i = 1; i <= n; i++)
        LOG[i] = LOG[i / 2] + 1;
}
template<typename T> void create(T f[][MAXNUM],T num[])
{
    for (int j = 1; j <= n; j++)
        f[0][j] = num[j];
    for (int i = 1; i <= 20; i++)
        for (int j = 1; j + (1 << i) - 1 <= n; j++)
            f[i][j] = max(f[i - 1][j], f[i - 1][j + (1 << (i - 1))]);
}
template<typename T> T query(T f[][MAXNUM],int qleft, int qright)
{
    int nLog = LOG[qright - qleft + 1];
    return max(f[nLog][qleft], f[nLog][qright - (1 << nLog) + 1]);
}
int res;
void solve(int l,int r)
{
    if(l>r)return;
    pii p=query(fnum,l,r);
    int mid=(l+r)/2;
    if(p.second<=mid)
    {
        rep(i,l,p.second+1)
            if(i+p.first-1<=r&&i+p.first-1>=p.second&&query(f,i,i+p.first-1)<i)
                res++;
    }
    else{
        rep(i,p.second,r+1)
            if(i-p.first+1>=l&&i-p.first+1<=p.second&&query(f,i-p.first+1,i)<i-p.first+1)
                res++;
    }
    solve(l,p.second-1),solve(p.second+1,r);
}
int main()
{
    scanf("%d",&n);
    getlist();
    rep(i,1,n+1)scanf("%d",&num[i].first),num[i].second=i;
    rep(i,1,n+1)
        per[i]=pos[num[i].first],pos[num[i].first]=i;
    create(f,per),create(fnum,num);
    solve(1,n);printf("%d\n",res);
}

你可能感兴趣的:(CF比赛)