Codeforces Round #216 (Div. 2)

以后争取补题不看别人代码,只看思路,今天就是只看思路补完的题,有点小激动。

A. Valera and Plates

水题,贪心地先放完第一种食物,在考虑第二种。

居然被卡了一会,心态要蹦 :(;

#include<bits/stdc++.h>
using namespace std;
int n,m,k;
int main()
{
    cin>>n>>m>>k;
    int cnt1=0,cnt2=0;
    for(int i=1;i<=n;i++)
    {
        int g; scanf("%d",&g);
        if(g==1) cnt1++;
        else cnt2++;
    }
    int ans=0;
    if(m<=cnt1) ans+=cnt1-m,m=0;
    else k+=(m-cnt1);
    ans+=max(0,cnt2-k);
    cout<<ans<<endl;
}

B. Valera and Contest

题目大意:给你n个数,你不知道第i个是多少,但是你知道里面数的最大值和最小值,所有数的和,

以及前k大个数的和,让你构造出这n个数。

思路:按平均数来构造,有余数补上,有一点wa了一次,取膜的时候没有考虑k==n的情况,用0取了膜,

以后不能犯这个错误了!!!

#include<bits/stdc++.h>
using namespace std;
int n,k,l,r,sa,sk;
int ans[10005];
int main()
{
    cin>>n>>k>>l>>r>>sa>>sk;
    int g=sk/k,sg=sk%k;
    int now=0;
    for(int i=1;i<=k;i++)
    {
        ans[i]=g;
        if(i<=sg) ans[i]++;
        now+=ans[i];
    }
    if(k<n)
    {
        int ssum=sa-sk;
        g=ssum/(n-k),sg=ssum%(n-k);
        for(int i=1;i<=n-k;i++)
        {
            ans[i+k]=g;
            if(i<=sg) ans[i+k]++;
        }
    }

    for(int i=1;i<=n;i++) printf("%d%c",ans[i],i==n? ‘\n‘:‘ ‘);
    return 0;
}

C. Valera and Elections

题目大意:有一棵树,有些边有问题,需要修复,修复的方法就是选出节点的子集,每个选中的节点

修复这个节点到 1 节点的所有有问题的边,问你最少需要选几个节点。

思路:还是比较好想的,直接从1开始dfs,用数组ans保存答案,top为其栈顶,每次dfs到一个节点,

先记录当前栈顶的值,回溯回来后,看当前栈顶是不是和第一次进入的时候一样,如果一样说明,

这个节点的下面没有有问题的边,如果这个节点通向其父节点的边是有问题的那么这个节点一定要选,

如果当前栈顶和第一次进入的时候不一样,说明这个节点的子节点中已经有一个作为答案了,

当前节点不需要选。

#include<bits/stdc++.h>
#define pii pair<int,int>
#define pb push_back
#define mk make_pair
#define fi first
#define se second
using namespace std;
const int N=1e5+5;
vector<pii> e[N];
int n,tot=0,ans[N];
void dfs(int u,int p,int pe)
{
    int now=tot;
    for(int i=0;i<e[u].size();i++)
    {
        pii to=e[u][i];
        if(to.fi==p) continue;
        dfs(to.fi,u,to.se);
    }
    if(pe==2 && tot==now) ans[++tot]=u;
}
int main()
{
    cin>>n;
    for(int i=1;i<n;i++)
    {
        int from,to,op;scanf("%d%d%d",&from,&to,&op);
        e[from].pb(mk(to,op));
        e[to].pb(mk(from,op));
    }
    dfs(1,-1,-1);
    cout<<tot<<endl;
    for(int i=1;i<=tot;i++) printf("%d%c",ans[i],i==tot?‘\n‘:‘ ‘);
    return 0;
}

D. Valera and Fools

题目大意:有n个笨蛋站在一排,每个人手里都有枪,他们的编号分别为1->n,每个人都有一个打死人

的概率(0-100)%,现在进行k轮游戏,每一轮,除编号最小的人朝编号第二小的人开枪,其他人都向

编号最小的人开枪,问你k轮之中有几种不同的情形,即活着的人不同的情况。

QAQ 不会写啊,知道是dp也不会写,看来我dp还是太弱了,该写写dp的专题了!!!

思路:我们首先要明确一点,第三大编号即以上的人一定是活着的,那么我们用dp[ i ][ j ],表示到达

最小编号为i 第二小编号为 j 的情形 最少需要几轮游戏。初始状态 dp[ 1 ][ 2 ]=0,这样就能写出状态

转移方程了。

#include<bits/stdc++.h>
using namespace std;
const int N=3005;
const int inf=0x3f3f3f3f;
int n,k,dp[N][N],p[N],mx[N];//mx[i] 表示i及以后概率的最大值。
int main()
{
    cin>>n>>k;
    for(int i=1;i<=n;i++) scanf("%d",&p[i]);
    for(int i=n;i>=1;i--) mx[i]=max(mx[i+1],p[i]);
    memset(dp,inf,sizeof(dp));
    dp[1][2]=0;
    for(int i=1;i<=n;i++)
    {
        for(int j=i+1;j<=n;j++)
        {
            if(dp[i][j]>=inf) continue;
            if(mx[j]>0 && p[i]<100) dp[j][j+1]=min(dp[j][j+1],dp[i][j]+1);
            if(p[i]>0 && mx[j]!=100) dp[i][j+1]=min(dp[i][j+1],dp[i][j]+1);
            if(mx[j]>0 && p[i]>0) dp[j+1][j+2]=min(dp[j+1][j+2],dp[i][j]+1);
        }
    }
    int ans=0;
    for(int i=1;i<=n+2;i++)//i,j如果大于n说明 只剩一个人或者没有人或者。
    {
        for(int j=i+1;j<=n+2;j++)
        {
            if(dp[i][j]<=k) ans++;

        }
    }
    printf("%d\n",ans);
    return 0;
}

E. Valera and Queries

题目大意:给你n条线段,然后又m组询问,每一组询问有cnt[ i ]个数,问你这些线段中有多少是

覆盖了这里面任意一个点的,覆盖1个2个...都可以。

一看就知道是线段树(树状数组)的题目,可是不会写啊!!

思路:我们可以很巧妙地转换一下,求覆盖的线段,可以先求一个点都没有覆盖的线段,然后总的

减去就好了,这样问题就变成了,给你的cnt[ i ]个点相邻的两个之间有多少条线段。这样我们就能用

树状数组了,先将线段按 r 值排序,注意如果是保存前缀,一定是要用 r 值排序的。每个树状数组的

节点保存,所管理的区域范围内的 l 的值,并将 l 值排好序。找位于相邻两点之间的线段数量时,

树状数组每个节点lower_bound一下就好了。

#include<bits/stdc++.h>
#define pii pair<int,int>
#define fi first
#define se second
#define mk make_pair
#define pb push_back
using namespace std;
const int N=3*1e5+5;
int n,m,top=1,x[N];//x 保存r的值,离散化的时候去重,排序。
vector<int> bt[N],o[N];
pii p[N];
bin_search(int tar)// 离散化,r真正地值查找对应的编号。
{
    int l=0,r=top;
    while(1)
    {
        int mid=(l+r)>>1;
        if(x[mid]==tar) return mid;
        else if(x[mid]<tar) l=mid+1;
        else r=mid-1;
    }
}
int low_bit(int u){return u&-u;}
void build()
{
    for(int i=1;i<top;i++)
    {
        int up=low_bit(i);
        for(int j=i;j>i-up;j--)
        {
            for(int k=0;k<o[j].size();k++)
            {
                int now=o[j][k];
                bt[i].pb(now);
            }
        }
        sort(bt[i].begin(),bt[i].end());
    }
}
int query(int u,int l)
{
    int sum=0;
    while(u>0)
    {
        int c=upper_bound(bt[u].begin(),bt[u].end(),l)-bt[u].begin();
        sum+=bt[u].size()-c;
        u-=low_bit(u);
    }
    return sum;
}
int main()
{
    cin>>n>>m;
    for(int i=0;i<n;i++)
    {
        scanf("%d%d",&p[i].fi,&p[i].se);
        x[top++]=p[i].se;
    }
    sort(x,x+top);
    top=unique(x,x+top)-x;
    for(int i=0;i<n;i++)
    {
        int g=bin_search(p[i].se);
        o[g].pb(p[i].fi);
    }
    build();
    int sum=0,q,p;
    while(m--)
    {
        sum=0;p=0;
        int cnt; scanf("%d",&cnt);
        for(int i=1;i<=cnt;i++)
        {
            scanf("%d",&q);
            int pos=lower_bound(x+1,x+top,q)-x;
            pos--;
            sum+=query(pos,p);
            p=q;
        }
        sum+=query(top-1,p);
        printf("%d\n",n-sum);
    }
    return 0;
}

ps: e题网上的作法貌似比我的快,用的也是树状数组,不过他是把题目原来的线段和后来两点间的

线段保存在一起,最后一起离线处理,把所有线段都按 l  的大小降序(如果 l 一样,r小的优先),这样

从头往后扫,这样就保证了后面的线段的 l 值不会大于前面的,这样只要看 r 值就行了,r的个数

保存在树状数组中。

时间: 2025-01-15 09:32:27

Codeforces Round #216 (Div. 2)的相关文章

Codeforces Round #216 (Div. 2) E. Valera and Queries (BIT)

题目大意: 给出很多条分布在 x 轴上的线段. 然后给出很多点集,问这些点集分布在多少条不同的线段上. 思路分析: 把点集分散成若干条线段. 如果点集做出的线段包含了某一条给出的线段的话,也就是说这个点集上不会有点在这条线段上. 所以我们就是求出 点集做出的线段包含了多少个给出的线段就可以了. 那么也就是比较l r的大小,排序之后用BIT #include <cstdio> #include <iostream> #include <algorithm> #includ

Codeforces Round #216 (Div. 2) E. Valera and Queries 树状数组 离线处理

题意:n个线段[Li, Ri], m次询问, 每次询问由cnt个点组成,输出包含cnt个点中任意一个点的线段的总数. 由于是无修改的,所以我们首先应该往离线上想, 不过我是没想出来. 首先反着做,先求不包含这个cnt个点的线段的总数, 那么不包含这些点的线段必然在cnt个点之间(这里需要再加两个点一个是0, 一个是MAX), 我们可以把所有线段按Ri 分类, 然后按右端点遍历,对于当前的线段可以在Li 处+1, 然后对于每一次询问中两个点(x, y)之间线段的个数, 只需要查询 左端点大于等于x

Codeforces Round #216 (Div. 2)---C. Valera and Elections

The city Valera lives in is going to hold elections to the city Parliament. The city has n districts and n?-?1 bidirectional roads. We know that from any district there is a path along the roads to any other district. Let's enumerate all districts in

Codeforces Round #279 (Div. 2) ABCD

Codeforces Round #279 (Div. 2) 做得我都变绿了! Problems # Name     A Team Olympiad standard input/output 1 s, 256 MB  x2377 B Queue standard input/output 2 s, 256 MB  x1250 C Hacking Cypher standard input/output 1 s, 256 MB  x740 D Chocolate standard input/

Codeforces Round #428 (Div. 2)

Codeforces Round #428 (Div. 2) A    看懂题目意思就知道做了 #include<bits/stdc++.h> using namespace std; #pragma comment(linker, "/STACK:102400000,102400000") #define rep(i,a,b) for (int i=a; i<=b; ++i) #define per(i,b,a) for (int i=b; i>=a; --i

Codeforces Round #424 (Div. 2) D. Office Keys(dp)

题目链接:Codeforces Round #424 (Div. 2) D. Office Keys 题意: 在一条轴上有n个人,和m个钥匙,门在s位置. 现在每个人走单位距离需要单位时间. 每个钥匙只能被一个人拿. 求全部的人拿到钥匙并且走到门的最短时间. 题解: 显然没有交叉的情况,因为如果交叉的话可能不是最优解. 然后考虑dp[i][j]表示第i个人拿了第j把钥匙,然后 dp[i][j]=max(val(i,j),min(dp[i-1][i-1~j]))   val(i,j)表示第i个人拿

Codeforces Round #424 (Div. 2) C. Jury Marks(乱搞)

题目链接:Codeforces Round #424 (Div. 2) C. Jury Marks 题意: 给你一个有n个数序列,现在让你确定一个x,使得x通过挨着加这个序列的每一个数能出现所有给出的k个数. 问合法的x有多少个.题目保证这k个数完全不同. 题解: 显然,要将这n个数求一下前缀和,并且排一下序,这样,能出现的数就可以表示为x+a,x+b,x+c了. 这里 x+a,x+b,x+c是递增的.这里我把这个序列叫做A序列 然后对于给出的k个数,我们也排一下序,这里我把它叫做B序列,如果我

[Codeforces] Round #352 (Div. 2)

人生不止眼前的狗血,还有远方的狗带 A题B题一如既往的丝帛题 A题题意:询问按照12345678910111213...的顺序排列下去第n(n<=10^3)个数是多少 题解:打表,输出 1 #include<bits/stdc++.h> 2 using namespace std; 3 int dig[10],A[1005]; 4 int main(){ 5 int aa=0; 6 for(int i=1;;i++){ 7 int x=i,dd=0; 8 while(x)dig[++dd

Codeforces Round #273 (Div. 2)

Codeforces Round #273 (Div. 2) 题目链接 A:签到,仅仅要推断总和是不是5的倍数就可以,注意推断0的情况 B:最大值的情况是每一个集合先放1个,剩下都丢到一个集合去,最小值是尽量平均去分 C:假如3种球从小到大是a, b, c,那么假设(a + b) 2 <= c这个比較明显答案就是a + b了.由于c肯定要剩余了,假设(a + b)2 > c的话,就肯定能构造出最优的(a + b + c) / 3,由于肯定能够先拿a和b去消除c,而且控制a和b成2倍关系或者消除