Codeforces Round #466 (Div. 2)

前言

感觉这场比赛全部提都是可以做的。。
但是我实在太菜,只做了四题,赛后做了两个。。
感觉策略上最近出了问题
每次都是做完前面2~3题就跳题做了
这一次写了abc,就没有看d,去搞e
又没搞出来
回来发现d题很简单的时候分数已经很少了
CF的得分策略来看,应该要把全部题看一次再决定吧
最后,这场比赛升了1分,看来我的实力还是没有达到紫名啊

题解

A

数据范围很小
枚举最小值,判断即可

B

每一个是k的倍数都是决策点
别的无脑减1
容易发现,这样的复杂度是log的
然后注意k=1的情况

C

很简单的题。。自己想把

D

也是很简单的题。。但是由于开始做的时候已经太晚了。。所以分数很低
就只需要考虑四种情况就可以了
自己看看代码吧

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
using namespace std;
const int MAX=1e9;
const int N=100005;
int n;
int a[N];
char ss[N];
int mx=1e9,mn=-1e9;
int l=MAX,L=-MAX;
int r=MAX,R=-MAX;
int main()
{
    scanf("%d",&n);
    for (int u=1;u<=n;u++) scanf("%d",&a[u]);
    scanf("%s",ss+1);
    for (int u=5;u<=n;u++)
    {
        if (ss[u]=='1')
        {
            if (ss[u]==ss[u-1])
            {
                int p=MAX;
                for (int i=0;i<=4;i++)
                    p=min(p,a[u-i]);
                R=max(r,p);
            }
            else
            {
                int p=-MAX;
                for (int i=0;i<=4;i++)
                    p=max(p,a[u-i]);
                L=max(L,p+1);
            }
        }
        else
        {
            if (ss[u]==ss[u-1])
            {
                int p=-MAX;
                for (int i=0;i<=4;i++)
                    p=max(p,a[u-i]);
                l=min(l,p);
            }
            else
            {
                int p=MAX;
                for (int i=0;i<=4;i++)
                    p=min(p,a[u-i]);
                r=min(r,p-1);
            }
        }
    }
    printf("%d %d\n",L,r);
    return 0;
}

E

看题看了很久才看懂。。感觉我的英语要凉凉
然后猜结论一直没有猜中QAQ
我觉得没猜中的原因是受了一开始看错题的影响。。
一开始猜的是选的肯定是k的倍数。。但是似乎不太对。。
然后就可以考虑对于每一个modk是同一个数的维护单调队列
但似乎并不可以做。。

首先可以证明出最优方案中一定存在所有划分的块的元素量都不大于c。假设最优方案中存在大于c的块,规模为d,d % c = k, d / c = m, k不为0时,额外加入的这k个元素并不会使得当前块被砍掉的元素数量增多,也不会使被砍掉的元素增大,因此把这k个元素独立出来不会使结果变差;当k等于0时,即d是c的m倍时,合并m个规模为c的块不会使总共被砍掉的m个元素便大,相反可能变小。

真是可惜了。。
当时硬是没有猜到这一个。。
一直在往错误的方向想。。
然后一直证不出来我要的东西
就GG了
有了这个结论,DP就很简单了
我们只需要考虑每一个个数达到c的区间就可以了
CODE:

#include<cstdio>
#include<algorithm>
#include<iostream>
#include<cstring>
#include<set>
using namespace std;
typedef long long LL;
const int N=100005;
multiset<int> s;
set<int> :: iterator it;
int n,c;
LL f[N];
int a[N];
int main()
{
    scanf("%d%d",&n,&c);
    LL sum=0;
    for (int u=1;u<=n;u++)  
    {
        scanf("%d",&a[u]);
        sum=sum+a[u];
    }
    for (int u=1;u<=n;u++)
    {
        f[u]=f[u-1];s.insert(a[u]);
        if (u>=c)
        {
            f[u]=max(f[u],f[u-c]+(*s.begin()));
            int tt=a[u-c+1];
            it=s.find(tt);
            s.erase(it);
        }
    }
    printf("%I64d\n",sum-f[n]);
    return 0;
}

F

想了一下都不会做
想过带修改莫队。。
不会的看这里
但是这种强行不 n2 n 2 的算法怎么可以A题嘛。。
于是就没写。。
没想到题解真的是这一个QAQ
至于怎么求解答案
容易知道,答案是根号级别的
于是随便枚举一下就好了

CODE:

#include<cstdio>
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cmath>
using namespace std;
const int N=100005*2;
int n,m;
int s[N];
int S[N];
int size;
struct qq
{
    int id;
    int l,r;
    int last;
}a[N],b[N];
int tot=0,tot1=0;
int Ans[N];
int belong[N];
bool cmp (qq x,qq y)
{
    if (belong[x.l]==belong[y.l])
    {
        if (belong[x.r]==belong[y.r]) return x.last<y.last;
        return belong[x.r]<belong[y.r];
    }
    return belong[x.l]<belong[y.l];
}
int l=1,r=0,o=0;//当前修改到了哪里
int vis[N];
int ans=0;
int tt[N];//这个出现次数有多少个 
void change1 (int now)//添加操作 
{
    int x=b[now].l,y=b[now].r;
    if (x>=l&&x<=r)
    {
        tt[vis[s[x]]]--;
        vis[s[x]]--;
        tt[vis[s[x]]]++;
        tt[vis[y]]--;
        vis[y]++;
        tt[vis[y]]++;
    }
    s[x]=y;
}
void change (int now)//删除 
{
    int x=b[now].l,y=b[now].last;
    if (x>=l&&x<=r)
    {
        tt[vis[s[x]]]--;
        vis[s[x]]--;
        tt[vis[s[x]]]++;
        tt[vis[y]]--;
        vis[y]++;
        tt[vis[y]]++;
    }
    s[x]=y;
}
void Add (int x)
{
    tt[vis[s[x]]]--;
    vis[s[x]]++;
    tt[vis[s[x]]]++;
}
void Del (int x){tt[vis[s[x]]]--;vis[s[x]]--;tt[vis[s[x]]]++;}
int A[N];
int Find (int l,int r,int x)
{
    while (l<=r)
    {
        int mid=(l+r)>>1;
        if (A[mid]==x) return mid;
        else if (A[mid]>x) r=mid-1;
        else l=mid+1;
    }
}
void LSH ()
{
    sort(A+1,A+1+A[0]);
    int lalal=1;
    for (int u=2;u<=A[0];u++)
        if (A[lalal]!=A[u])
            A[++lalal]=A[u];
    for (int u=1;u<=n;u++)
        s[u]=Find(1,lalal,s[u]);
    for (int u=1;u<=tot1;u++)
    {
        b[u].r=Find(1,lalal,b[u].r);
        b[u].last=Find(1,lalal,b[u].last);
    }
}
int main()
{
    scanf("%d%d",&n,&m);
    size=pow(n,0.66666);
    for (int u=1;u<=n;u++)  belong[u]=(u-1)/size+1;
    for (int u=1;u<=n;u++) 
    {
        scanf("%d",&s[u]),S[u]=s[u];
        A[++A[0]]=s[u];
    }
    for (int u=1;u<=m;u++)
    {
        int x;
        scanf("%d",&x);
        if (x==1)
        {
            tot++;
            scanf("%d%d",&a[tot].l,&a[tot].r);
            a[tot].id=tot;
            a[tot].last=tot1;
        }
        else
        {
            tot1++;
            scanf("%d%d",&b[tot1].l,&b[tot1].r);
            A[++A[0]]=b[tot1].r;
            b[tot1].last=S[b[tot1].l];
            S[b[tot1].l]=b[tot1].r;
        }
    }
    LSH();
    sort(a+1,a+1+tot,cmp);
    memset(tt,0,sizeof(tt));
    memset(vis,0,sizeof(vis));
    for (int u=1;u<=tot;u++)
    {
        while (o<a[u].last) change1(++o);
        while (o>a[u].last) change(o--);
        while (r<a[u].r) Add(++r);
        while (l>a[u].l) Add(--l);
        while (l<a[u].l) Del(l++);
        while (r>a[u].r) Del(r--);
        for (int i=1;;i++)
            if (tt[i]==0)
            {
                Ans[a[u].id]=i;
                break;
            }
    }
    for (int u=1;u<=tot;u++)    printf("%d\n",Ans[u]);
    return 0;                     
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值