首页 > 代码库 > Codeforces Round #381 (Div. 2)

Codeforces Round #381 (Div. 2)

今天模拟了一套,被c题卡死了WCCCCCCCC。

 

A - Alyona and copybooks

题目大意:mike有 n 本书,他需要买到4的倍数本书,买一本书需要a元,二本b元,三本c元,

问你最少需要多少钱。

 

思路:水题,一共只有4种情况n对四 余 1,2,3,4。 枚举一下就好了。

技术分享
#include<bits/stdc++.h>
#define ll long long
using namespace std;
ll n,a,b,c;
int main()
{
    cin>>n>>a>>b>>c;
    ll ans=1e18;
    if(n%4==0)
    {
        ans=0;
    }
    else if(n%4==3)
    {
        ans=min(ans,a);
        ans=min(ans,3*c);
        ans=min(ans,b+c);
    }
    else if(n%4==2)
    {
        ans=min(ans,2*a);
        ans=min(ans,b);
        ans=min(ans,2*c);
    }
    else if(n%4==1)
    {
        ans=min(ans,c);
        ans=min(ans,3*a);
        ans=min(ans,a+b);
    }
    cout<<ans<<endl;
    return 0;
}
View Code

 

B - Alyona and flowers

题目大意:有n个数,给你m个区间,让你选择若干个区间覆盖区间中的点,这些数的价值为

各个数字与其覆盖次数乘积的和,问你价值最大是多少。

 

思路:判断一个区间要不要覆盖就是,判断覆盖后整体的值是变大还是变小,这样思路就很

明确了。

技术分享
#include<bits/stdc++.h>
using namespace std;
int w[105],cnt[105],sum[105];
int n,m;
int main()
{
    cin>>n>>m;

    for(int i=1;i<=n;i++) scanf("%d",&w[i]),sum[i]=sum[i-1]+w[i];
    while(m--)
    {
        int l,r; scanf("%d%d",&l,&r);
        if(sum[r]-sum[l-1]>0)
        for(int i=l;i<=r;i++) cnt[i]++;
    }
    int ans=0;
    for(int i=1;i<=n;i++) ans+=cnt[i]*w[i];
    printf("%d\n",ans);
    return 0;
}
View Code

 

C - Alyona and mex

题目大意:有n个数,定义mex( l , r )运算为在l -> r 中未出现过的最小自然数,给你 m 个区间

让你构造出这n个数,使mex值最小区间的值最大。

 

妈的,疯狂宕机,我是猪脑子吧???!!!!

我一直在考虑如何使每个区间都最优,就这样想了一个半小时,得出一个结论,这题我不会写,

我他妈的******************************。

 

思路:其实我们只需要将每个区间都保证其mex值大于等于最小的mex值,其中区间mex最小

的最大值,肯定是其区间的长度,设这个值为x。所以我们只要保证所有区间mex大于等于x

就行了,我们只需要从第一个数开始给他们赋值,0,1,……,x-1,这样一个循环赋值就好了。

 

技术分享
#include<bits/stdc++.h>
using namespace std;
int n,m;
int main()
{
    cin>>n>>m;
    int mn=n;
    while(m--)
    {
        int l,r; scanf("%d%d",&l,&r);
        mn=min(mn,r-l+1);
    }
    int now=0;
    cout<<mn<<endl;
    for(int i=1;i<=n;i++)
    {
        cout<<now++<<" ";
        if(now==mn) now=0;
    }
    return 0;
}
View Code

 

D - Alyona and a tree

题目大意:给你一棵以 1 为根的树每棵树都有一个权值a[ i ],每条边也有一个权值e[ i ],一个

节点u 管理 一个节点 v的条件是,1.  v 是 u 的子节点,2. 从 u 到 v 的所有边的权值和小于

v 的权值和。 问你每个节点管理多少个节点。

 

我感觉这题是个好题,我学到好多啊。

 

思路:我们设 d( u ) 表示 1 到 u 边的权值和,那么 u 管理 v 可以表示成 d( v ) - d( u ) <= a[ v ]

我们可以移项得到,d( v ) - a[ v ] <= d( u ),这样我们能保存路径,用lower_bound找到第一个

小于d( v ) - a[ v ]的 d( u ),那样问题就变成了怎么更新,我们可以利用类似于前缀和的思想,

用ans[ i ]来保存答案,是找到的那个 u 的ans[ u ]减去一,这样我们在回溯的时候,他的父节点

及他的祖宗都减去一了,然后我们每次dfs下一个节点回来的时候,设当前节点为a,刚从节点

b回溯回来,那么我们就 ans[ a ]+=ans[ b ]+1;这样我们通过继续回溯,就能将 a 的父节点及

祖宗全部都加上一,可以这么想,如果没有之前的lower_bound找节点减去1,之后后边的

加一,那么ans[ i ]的值就是,i 下面所有的子节点。

 

技术分享
#include<bits/stdc++.h>
#define ll long long
#define pii pair<ll,int>
#define pb push_back
#define mk make_pair
#define fi first
#define se second
using namespace std;
const int N=2*1e5+5;
vector<pii> e[N],r;//r 保存当前的路径。
int n;
ll a[N],ans[N],d[N];
void dfs(int u)
{
    r.pb(mk(d[u],u));
    int t=lower_bound(r.begin(),r.end(),mk(d[u]-a[u],-1))-r.begin()-1;
    if(t>=0) ans[r[t].se]--;//找到的点的ans-1,通过回溯,其上面的节点也都-1了。
    for(int i=0;i<e[u].size();i++)
    {
        pii v=e[u][i];
        d[v.se]=d[u]+v.fi;
        dfs(v.se);
        ans[u]+=ans[v.se]+1;//使u这个节点的ans加上v这个点的ans,回溯使u上面的节点都加上了v
    }
    r.pop_back();
}
int main()
{
    cin>>n;
    for(int i=1;i<=n;i++) scanf("%I64d",&a[i]);
    for(int i=2;i<=n;i++)
    {
        int p;
        ll w;
        scanf("%d%I64d",&p,&w);
        e[p].pb(mk(w,i));
    }
    dfs(1);
    for(int i=1;i<=n;i++) printf("%I64d%c",ans[i],i==n ? \n: );
    return 0;
}
View Code

 

Codeforces Round #381 (Div. 2)