ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

Codeforces Round #737 (Div. 2) A~E 题解

2021-08-15 10:00:47  阅读:250  来源: 互联网

标签:qpow int 题解 ll Codeforces res Div define MOD


本场链接:Codeforces Round #737 (Div. 2)

闲话

做的时候把C的条件转错了白做一个多小时.最后E由于假了所以就不写了,有兴趣自己补吧.

A. Ezzat and Two Subsequences

考虑平均值:最大值所在的组,会因为放入别的数而变小.每个数都需要在一个组,不难想到使最大值单独成一个组即可.

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define forn(i,x,n) for(int i = x;i <= n;++i)
#define forr(i,x,n) for(int i = n;i >= x;--i)
#define Angel_Dust ios::sync_with_stdio(0);cin.tie(0)

const int N = 1e5+7;
ll a[N];

int main()
{
    int T;scanf("%d",&T);
    while(T--)
    {
        int n;scanf("%d",&n);
        forn(i,1,n) scanf("%lld",&a[i]);
        sort(a + 1,a + n + 1);
        ll sum = 0;forn(i,1,n - 1)  sum += a[i];
        printf("%.18lf\n",a[n] + 1.0 * sum / (n - 1));
    }
    return 0;
}

B. Moamen and k-subarrays

一段数可以在一起不动,当且仅当他们是连续增大的.为了方便不妨先把所有数映射成他们的rank,如此条件就等价于一段连续增大的段.求出段数\(cnt\)当\(cnt \leq k\)时可以划分.

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define forn(i,x,n) for(int i = x;i <= n;++i)
#define forr(i,x,n) for(int i = n;i >= x;--i)
#define Angel_Dust ios::sync_with_stdio(0);cin.tie(0)

const int N = 1e5+7;
int a[N],d[N];

bool cmp(int x,int y)
{
    return a[x] < a[y];
}

int main()
{
    int T;scanf("%d",&T);
    while(T--)
    {
        int n,k;scanf("%d%d",&n,&k);
        forn(i,1,n) scanf("%d",&a[i]),d[i] = i;
        sort(d + 1,d + n + 1,cmp);
        forn(i,1,n) a[i] = d[i];

        int cnt = 0;
        forn(i,1,n)
        {
            int j = i;
            while(j + 1 <= n && a[j + 1] == a[j] + 1)    ++j;
            ++cnt;
            i = j;
        }
        if(cnt <= k)    puts("yes");
        else puts("no");
    }
    return 0;
}

C. Moamen and XOR

原条件可以看做是有两种情况:要么相同要么严格大于.如果严格大于说明存在某一位\(k\)在此位上左部严格大于右部,这样只能是1/0的情形,同时前半部分完全相同,后半部分随意填充.

前半部分完全相同,分奇偶考虑组合数,后半部分随意填显然是\(2\)的长度幂次.如此,枚举一个前缀相同,直到某一位产生严格大即可.(其实还能注意到\(n\)为奇数的时候可以直接有一个答案公式).

在实现的时候写\(0\)下标会好写一些.

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define forn(i,x,n) for(int i = x;i <= n;++i)
#define forr(i,x,n) for(int i = n;i >= x;--i)
#define Angel_Dust ios::sync_with_stdio(0);cin.tie(0)

const int MOD = 1e9+7;
ll qpow(ll a,ll b,ll MOD)
{
    ll res = 1;
    while(b)
    {
        if(b & 1)   res = res * a % MOD;
        a = a * a % MOD;
        b >>= 1;
    }
    return res;
}

int main()
{
    int T;scanf("%d",&T);
    while(T--)
    {
        int n,k;scanf("%d%d",&n,&k);
        if(k == 0) 
        {
            puts("1");
            continue;
        }
        if(n == 1)
        {
            printf("%lld\n",qpow(2,k,MOD));
            continue;
        }
        if(n % 2 == 1)
        {
            ll res = qpow(2,n - 1,MOD) + 1;
            res = qpow(res,k,MOD);
            printf("%lld\n",res);
        }
        else
        {
            ll res = qpow(2,k - 1,MOD);
            res = qpow(res,n,MOD);
            ll _ = qpow(2,n - 1,MOD);
            _ = ((_ - 1) % MOD + MOD) % MOD;
            _ = qpow(_,k,MOD);
            res = (res + _) % MOD;
            forn(j,1,k - 1)
            {
                ll nxt = ((qpow(2,n - 1,MOD) - 1) % MOD + MOD) % MOD;
                nxt = qpow(nxt,j,MOD);
                ll oth = qpow(2,n,MOD);
                oth = qpow(oth,k - j - 1,MOD);
                nxt = nxt * oth % MOD;
                res = (res + nxt) % MOD;
            }
            printf("%lld\n",res);
        }
    }
    return 0;
}

D. Ezzat and Grid

数据范围很吊比,先不看那么多,考虑直接做:每一行有删和不删两种决策,而且由于删这个操作不好表达信息,考虑计算保留行数:

  • 状态:\(f[i]\)表示前\([1,i]\)行中最多可以保留的行数.但是有个问题,这样没有前面状态在哪一行有\(1\)可以贴上去的信息,如此:\(f[i][j]\)表示前\([1,i]\)行中,强制保留第\(i\)行且第\(i\)行第\(j\)列有\(1\)的最多保留数.
  • 入口:全部置\(0\)即可.
  • 转移:考虑第\(i\)行保留下来的转移方式:若第\(k\)行的第\(j\)列与\(i\)行的第\(j\)列同时存在,则可以从\(f[k][j]\)转移到\(f[i][j]\).
  • 出口:枚举最大值即可.

这样直接做显然复杂度会达到\(O(n^2)\).可以发现\(j\)维的转移事实上等价于在区间上加和以及求区间上的最值.所以可以开一个线段树维护\(j\)维,将每一层一段\(1\)看做是一个区间求最值的操作(由前面的行转移而来),每层做完之后对本行做覆盖.

但是本题还需要求方案,常规来说,只需记录\(f[i]\)的转移前驱是谁即可,即维护一个\(succ[i]\)表示\(f[i]\)是由那个状态转移来的.在线段树上维护最值得同时维护最值来源的下标即可找到上一个保留的行具体是谁,如此即可找出在最优方案中具体保留了哪些行.即可将答案输出.

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
#define forn(i,x,n) for(int i = x;i <= n;++i)
#define forr(i,x,n) for(int i = n;i >= x;--i)
#define Angel_Dust ios::sync_with_stdio(0);cin.tie(0)
#define l first
#define r second

const int N = 1e6+7,INF = 1e9;
const pii PZ = {0,-1};
vector<int> vals;
vector<pii> E[N];
int PID[N],st[N];

struct Node
{
	int l,r;
    pii v,lazy;
}tr[N * 4];


inline int link(int x)
{
    return lower_bound(vals.begin(),vals.end(),x) - vals.begin() + 1;
}

void pushup(int u)
{
    tr[u].v = max(tr[u << 1].v,tr[u << 1 | 1].v);
}

void pushdown(int u)
{
    auto& lf = tr[u << 1],&s = tr[u],&rt = tr[u << 1 | 1];
    if(s.lazy == PZ)    return ;
    s.v = max(s.v,s.lazy);
    lf.lazy = max(lf.lazy,s.lazy);lf.v = max(lf.v,lf.lazy);
    rt.lazy = max(rt.lazy,s.lazy);rt.v = max(rt.v,rt.lazy);
    s.lazy = PZ;
}

void build(int u,int l,int r)
{
    if(l == r)  tr[u] = {l,r,PZ,PZ};
    else
    {
        int mid = l + r >> 1;
        tr[u] = {l,r};
        build(u << 1,l,mid),build(u << 1 | 1,mid + 1,r);
        pushup(u);
    }
}

void modify(int u,int l,int r,pii& v)
{
    if(tr[u].l >= l && tr[u].r <= r)
    {   
        tr[u].v = max(tr[u].v,v);
        tr[u].lazy = max(tr[u].lazy,v);
        return ;
    }
    pushdown(u);
    int mid = tr[u].l + tr[u].r >> 1;
    if(l <= mid)    modify(u << 1,l,r,v);
    if(r > mid)     modify(u << 1 | 1,l,r,v);
    pushup(u);
}

pii query(int u,int l,int r)
{
    if(tr[u].l >= l && tr[u].r <= r)    return tr[u].v;
    int mid = tr[u].l + tr[u].r >> 1;pii res = PZ;
    pushdown(u);
    if(l <= mid)    res = max(res,query(u << 1,l,r));
    if(r > mid)     res = max(res,query(u << 1 | 1,l,r));
    return res;
}

int main()
{
    memset(PID,-1,sizeof PID);
    int n,m;scanf("%d%d",&n,&m);
    forn(i,1,m)
    {
        int p,l,r;scanf("%d%d%d",&p,&l,&r);
        vals.push_back(l);vals.push_back(r);
        E[p].push_back({l,r});
    }
    
    sort(vals.begin(),vals.end());
    vals.erase(unique(vals.begin(),vals.end()),vals.end());

    forn(i,1,n) for(auto& _ : E[i]) _.l = link(_.l),_.r = link(_.r);
    build(1,1,N - 1);

    forn(i,1,n)
    {
        if(E[i].empty())    continue;
        pii mx = PZ;
        for(auto& _ : E[i]) mx = max(mx,query(1,_.l,_.r));
        // modify(1,1,N - 1,mx);
        PID[i] = mx.r;
        ++mx.l;
        mx.r = i;
        for(auto& _ : E[i]) modify(1,_.l,_.r,mx);
    }

    pii res = query(1,1,N - 1);
    int cur = res.r;
    while(cur != -1)
    {   
        st[cur] = 1;
        cur = PID[cur];
    }

    printf("%d\n",n - res.l);
    forn(i,1,n) if(!st[i])  printf("%d ",i);
    puts("");
    return 0;
}

标签:qpow,int,题解,ll,Codeforces,res,Div,define,MOD
来源: https://www.cnblogs.com/HotPants/p/15142721.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有