Educational Codeforces Round 93 (Rated for Div. 2)

A - Bad Triangle

选出三个序列使之不能组成三角形。先把差距最大的选了,枚举中间值。两边之和不大于第三边。

#define IO ios::sync_with_stdio(false);cin.tie();cout.tie(0)
#include
#include
using namespace std;
const int N=50010;
int a[N];
int main()
{
    IO;
    int T;
    cin>>T;
    while(T--)
    {
        int n;
        cin>>n;
        for(int i=1;i<=n;i++) cin>>a[i];
        int i;
        for(i=2;i<n;i++) 
            if(a[1]+a[i]<=a[n])
                break;
        if(i==n) cout<<-1<<endl;
        else cout<<1<<' '<<i<<' '<<n<<endl;
    }
    return 0;
}

B - Substring Removal Game

第一次没加#includeCompilation error了。。
考虑原串中连续的1。两人一定轮流选择目前连续1个数最多的。把连续的1个数存到一个数组,逆序。两人轮流取即可。

#define IO ios::sync_with_stdio(false);cin.tie();cout.tie(0)
#include
#include
#include
#include
#include
using namespace std;
const int N=110;
int a[N];
int main()
{
    IO;
    int T;
    cin>>T;
    while(T--)
    {
        string s;
        cin>>s;
        int n=s.size();
        vector<int> ans(n);
        for(int i=1;i<=n;i++) a[i]=s[i-1]-'0';
        for(int i=1;i<=n;i++)
        {
            int j=i;
            while(j<=n&&a[i]==a[j]) j++;
            if(a[i]==1) ans.push_back(j-i);
            i=j-1;
        }
        int res=0;
        sort(ans.begin(),ans.end());
        reverse(ans.begin(),ans.end());
        for(int i=0;i<ans.size();i++) 
            if(i%2==0) res+=ans[i];
        cout<<res<<endl;
    }
    return 0;
}

C - Good Subarrays

对于原数组 a [ l + 1 ] + a [ l + 2 ] + ⋯ + a [ r ] = r − l + 1 a[l+1]+a[l+2]+\dots+a[r]=r-l+1 a[l+1]+a[l+2]++a[r]=rl+1考虑前缀和数组即 a [ r ] − a [ l ] = r − l a[r]-a[l]=r-l a[r]a[l]=rl变换一下 a [ r ] − r = a [ l ] − l a[r]-r=a[l]-l a[r]r=a[l]l。因此只需统计 a [ i ] − i a[i]-i a[i]i的个数,根据组合数的计算公式即可。由于可能有负数弄了个map映射。上述情况未考虑i=0的情况,因此最后应加上a[i]==i的个数。

#define IO ios::sync_with_stdio(false);cin.tie();cout.tie(0)
#include
#include
#include
#include
#include
#include
#include
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
const int N=100010;
int a[N];
map<int,int> mp;
int idx=0;
int get(int s)
{
    if(!mp.count(s)) mp[s]=++idx;
    return mp[s];
}
ll cnt[N];
int main()
{
    IO;
    int T;
    cin>>T;
    while(T--)
    {
        
        int n;
        cin>>n;
        mp.clear();
        for(int i=0;i<=n;i++) cnt[i]=0;
        idx=0;
        string s;
        cin>>s;
        for(int i=1;i<=n;i++) a[i]=s[i-1]-'0';
        for(int i=1;i<=n;i++) a[i]+=a[i-1];
        for(int i=1;i<=n;i++) cnt[get(a[i]-i)]++;
        ll res=0;
        for(int i=1;i<=idx;i++) res+=1ll*cnt[i]*(cnt[i]-1)/2;
        for(int i=1;i<=n;i++)
            if(a[i]==i) res++;
        cout<<res<<endl;
    }
    return 0;
}

这题很快就想到怎么写了,但是码代码能力还是不行写了半天。最开始没想用map弄明白数组开多大烦死了(负数可以平移)然后就用map了。看群里讨论发现负数不一定平移,可以为负数多开一个数组记录a[-i],i<0

D - Colored Rectangles

首先贪心,对于每一对木条,肯定选择长的。因此先降序排列数组。
f[i][j][k]表示:R用了i个,G用了j个,B用了k个的集合。转移考虑最后用的是那一对木棒。

#define IO ios::sync_with_stdio(false);cin.tie();cout.tie(0)
#include
#include
#include
#include
#include
#include
#include
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
const int N=210;
int a[N],b[N],c[N];
int f[N][N][N];
int cnta,cntb,cntc;
int main()
{
    IO;
    cin>>cnta>>cntb>>cntc;
    for(int i=1;i<=cnta;i++) cin>>a[i];
    for(int i=1;i<=cntb;i++) cin>>b[i];
    for(int i=1;i<=cntc;i++) cin>>c[i];
    sort(a+1,a+1+cnta);
    sort(b+1,b+1+cntb);
    sort(c+1,c+1+cntc);
    reverse(a+1,a+1+cnta);
    reverse(b+1,b+1+cntb);
    reverse(c+1,c+1+cntc)for(int i=0;i<=cnta;i++)
        for(int j=0;j<=cntb;j++)
            for(int k=0;k<=cntc;k++)
            {
                if(i&&j&&(i+j+k)%2==0) f[i][j][k]=max(f[i][j][k],f[i-1][j-1][k]+a[i]*b[j]);
                if(j&&k&&(i+j+k)%2==0) f[i][j][k]=max(f[i][j][k],f[i][j-1][k-1]+c[k]*b[j]);
                if(i&&k&&(i+j+k)%2==0) f[i][j][k]=max(f[i][j][k],f[i-1][j][k-1]+a[i]*c[k]);
            }
    int res=0;
    for(int i=0;i<=cnta;i++) res=max(res,f[i][cntb][cntc]);
    for(int i=0;i<=cntb;i++) res=max(res,f[cnta][i][cntc]);
    for(int i=0;i<=cntc;i++) res=max(res,f[cnta][cntb][i]);
    cout<<res<<endl;
    return 0;
}

D题最后1分钟提交的太惊险了。

E-Two Types of Spells

群里大佬说是权值线段树+离散化,这个我学过补一下吧。
如果有klightning,那么能过翻倍k-1或者k个伤害(讨论一下),翻倍肯定翻倍最大的几个,因此考虑权值线段树(因此需要离散化)维护前k大,一般有删除加入需要用set维护,数据无重复,让题目简单不少。
lower_bound只能够在升序情况下使用

#define IO ios::sync_with_stdio(false);cin.tie();cout.tie(0)
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
const int N=200010;
int n;
pii q[N];
vector<int> id;
struct node
{
    int l,r,cnt;
    ll sum;
}tree[N*4];
int get(int a)
{
    int l=0,r=id.size()-1;
    
    while(l<r)
    {
        int mid=l+r>>1;
        if(id[mid]<=a) r=mid;
        else l=mid+1;
    }
    return l+1;
}
void pushup(int u)
{
    tree[u].cnt=tree[u<<1].cnt+tree[u<<1|1].cnt;
    tree[u].sum=tree[u<<1].sum+tree[u<<1|1].sum;
    
}
void build(int u,int l,int r)
{
    tree[u]={l,r,0,0};
    if(l==r) return;
    int mid=l+r>>1;
    build(u<<1,l,mid),build(u<<1|1,mid+1,r);
}
void modify(int u,int k,int x)
{
    if(tree[u].l==tree[u].r)
    {
        tree[u].cnt+=x;
        tree[u].sum+=x*id[k-1];
        return;
    }
    int mid=tree[u].l+tree[u].r>>1;
    if(k<=mid) modify(u<<1,k,x);
    else modify(u<<1|1,k,x);
    pushup(u);
}
ll query(int u,int k)
{
    if(tree[u].l==tree[u].r) return tree[u].sum;
    int tmp=tree[u<<1].cnt;
    if(tmp>=k) return query(u<<1,k);
    else return tree[u<<1].sum+query(u<<1|1,k-tmp);
}
int main()
{
    IO;
    cin>>n;
    build(1,1,n);
    for(int i=1;i<=n;i++)
    {
        cin>>q[i].first>>q[i].second;
        id.push_back(abs(q[i].second));
    }
    sort(id.begin(),id.end());
    id.erase(unique(id.begin(),id.end()),id.end());
    reverse(id.begin(),id.end());
    set<int> fire,lightning;
    int k=0;
    ll res=0;
    for(int i=1;i<=n;i++)
    {
        if(q[i].first==1)
        {
            if(q[i].second>0)
            {
                k++;
                lightning.insert(q[i].second);
                res+=q[i].second;
                modify(1,get(q[i].second),1);
            }
            else
            {
                k--;
                lightning.erase(-q[i].second);
                res+=q[i].second;
                modify(1,get(-q[i].second),-1);
            }
            
        }
        else
        {
            if(q[i].second>0)
            {
                fire.insert(q[i].second);
                res+=q[i].second;
                modify(1,get(q[i].second),1);
            }
            else
            {
                fire.erase(-q[i].second);
                res+=q[i].second;
                modify(1,get(-q[i].second),-1);
            }
        }
        if(fire.empty())
        {
            if(k>1)
                cout<<res+query(1,k-1)<<'\n';
            else cout<<res<<'\n';
        }
        else if(lightning.empty()) cout<<res<<'\n';
        else
        {
            
            int minl=*lightning.begin();
            auto t=fire.end();
            t--;
            int maxf=*t;
            if(minl>maxf)
            {
                if(k>1) cout<<res+query(1,k-1)+maxf<<'\n';
                else cout<<res+maxf<<'\n';
            }
            else
            {
                if(k>0) cout<<res+query(1,k)<<'\n';
                else cout<<res<<'\n';
            }
        }
    }
    return 0;
}

要加油哦~

你可能感兴趣的:(Codeforces)