Codeforces Round #310 (Div. 2)

Problem A:

题目大意:给你一个由0,1组成的字符串,如果有相邻的0和1要消去,问你最后还剩几个字符。

写的时候不想看题意直接看样例,结果我以为是1在前0在后才行,交上去错了。。后来仔细

看了看,哎。以后不能自以为是啊。

#include<bits/stdc++.h>
using namespace std;
const int N=2*1e5+2;
char s[N];
bool vis[N];
int main()
{
    int n;
    scanf("%d%s",&n,s);
    int cnt=n;
    int cnt1=0,cnt0=0;
    for(int i=0;i<n;i++)
    {
        if(s[i]=='0') cnt0++;
        else cnt1++;
    }
    printf("%d
",max(cnt0-cnt1,cnt1-cnt0));
}
View Code

Problem B:

题目大意:给你n个一排的齿轮,每个齿轮有编号(0->n-1)的锯齿,问你能不能转动第一个轮子,

使其向上的锯齿依次为,0,1,2,3...n-1。水题,你就把第一个齿轮转到0的次数记录下来,第偶数

个加上,奇数个减去,判断一下。

#include<bits/stdc++.h>
using namespace std;
const int N=1005;
int a[N];
int main()
{
    int n;
    cin>>n;
    for(int i=0;i<n;i++) scanf("%d",&a[i]);
    int cnt=n-a[0];
    //printf("%d
",cnt);
    for(int i=1;i<n;i++)
    {
        if(i%2)
        {
            if((a[i]-cnt+n)%n!=i)
            {
                puts("No");
                return 0;
            }
        }
        else
        {
            if((a[i]+cnt+n)%n!=i)
            {
                puts("No");
                return 0;
            }
        }
    }
    puts("Yes");
    return 0;
}
View Code

Problem C:

题目大意:给你n个编号1->n的杯子,编号代表了它们的大小,只有大的能套在小的上,现在

给你这些杯子现在的情况,让你把他变成1<-2<-3<-4....<-n这种形式需要操作几次。简单模拟

一下就好了。

#include<bits/stdc++.h>
using namespace std;
int n,k,ans,st;
int pre[100005];
void Find(int x)
{
    if(pre[x]!=x)
    {
        Find(pre[x]);
        ans++;
        pre[x]=x;
    }
}
void judge(int now,int p)
{
    if(now==p+1 || p==-1)
    {
        st=now;
        judge(pre[now],now);
    }
}
int main()
{
    cin>>n>>k;
    for(int i=1;i<=n;i++) pre[i]=i;
    for(int i=1;i<=k;i++)
    {
        int m;
        scanf("%d",&m);
        int p=-1;
        while(m--)
        {
            int g;
            scanf("%d",&g);
            if(p!=-1)
            {
                pre[p]=g;
            }
            p=g;
        }
    }
    ans=0;
    st=1;
    judge(1,-1);
    Find(st);
    for(int i=st+1;i<=n;i++)
    {
        Find(i);
        pre[i-1]=i;
        ans++;
    }
    cout<<ans<<endl;
    return 0;
}
View Code

Problem D:

题目大意:有n个排成以行的小道他们的范围分别是(l[i]->r[i])且l[i+1]>r[i],现在有m个长度为b[i]的桥

两个岛能加上长度为a的桥当且仅当 r[i+1]-l[i]>=a>=l[i+1]-r[i]。问你能不能完成这个工作。

这个题很显然,可以转换成这个问题:有n-1个区间,m个数,每个数最多只能用一次,第i个数只

要能被第j个区间包含,那么这个数就可以放入这个区间内。求出,当所有区间里都恰有一个数时的情况。

我写的时候一直在想固定最大范围和最小范围来贪心,用桥去满足他们,这种方法是不对的。

思路:我们可以将区间按按l排序,桥按长度排序,然后将当前满足 r>=a>=l 的区间都加到优先队列

里面,每次取出r最小的区间,这个桥就搭在这个区间上,为什么呢,因为对于优先队列里面的区间

来说,当前及以后的桥都满足,len[i]>=l 所以可以不用考虑区间的l,这样我们显然就可以贪心地取

r小的区间。

#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int N=2*1e5+5;
struct node
{
    ll mx,mn;
    int id;
    bool operator <(const node&t) const
    {
        return mx>t.mx;
    }
}w[N];
bool cmp(node a,node b)
{
    return a.mn<b.mn;
}
struct num
{
    ll v;
    int id;
    bool operator <(const num &t)const
    {
        return v<t.v;
    }
}a[N];
ll ans[N];
int n,m;
int main()
{
    cin>>n>>m;
    ll pl=-1,pr=-1;
    for(int i=0;i<n;i++)
    {
        ll l,r;
        scanf("%I64d%I64d",&l,&r);
        if(pl!=-1)
        {
            //printf("%d**
",i);
            w[i].mx=r-pl;
            w[i].mn=l-pr;
            w[i].id=i;
        }
        pl=l,pr=r;
    }
    for(int i=1;i<=m;i++)
    {
        scanf("%I64d",&a[i].v);
        a[i].id=i;
    }
    sort(a+1,a+1+m);
    sort(w+1,w+n,cmp);
    //for(int i=1;i<=m;i++) printf("%I64d ",a[i].v);
    //puts("");
    //for(int i=1;i<n;i++) printf("[%I64d,%I64d] ",w[i].mn,w[i].mx);
    priority_queue<node> Q;
    int cnt=0;
    for(int i=1,j=1;i<=m;i++)
    {
        while(w[j].mn<=a[i].v && a[i].v<=w[j].mx && j<n)
        {
            Q.push(w[j]);
            j++;
        }
        if(Q.empty()) continue;
        node now=Q.top();Q.pop();
        if(a[i].v>now.mx)
        {
            puts("No");
            return 0;
        }
        ans[now.id]=a[i].id;
        cnt++;
    }
    //printf("%d
",cnt);
    if(cnt<n-1)
    {
        puts("No");
        return 0;
    }
    puts("Yes");
    for(int i=1;i<n;i++) printf("%I64d%c",ans[i],i==n-1?'
' : ' ');
    return 0;
}
View Code

problem E:

题意:

有一块n*n大小的巧克力,n<=1e9。现在进行操作,每次都从反对角线上选择一点,然后往上或往左一直吃,

每当到达巧克力边缘或者下一块已经被吃了,则停止。问你每次操作能吃到几块巧克力。

思维题,感觉挺难想到了,还是我太菜了。。

思路:我们考虑从j列往上吃巧克力,吃掉的个数受什么影响呢,肯定不受<j的列印象,对它有直接影响的就

他右边第一个有操作的点,如果这个点的操作时向左吃,则从j列向上吃只能吃到有操作点的那一行,如果右边

第一个有操作的点是向上吃,则j列吃的和它一样。

#include<bits/stdc++.h>
using namespace std;
map<int,int> u,l;
int n,q;
int main()
{
    cin>>n>>q;
    while(q--)
    {
        int x,y;
        char s[3];
        scanf("%d%d%s",&x,&y,s);
        map<int,int>::iterator p;
        if(s[0]=='U')
        {
            int ans=0;
            p=u.lower_bound(x);
            if(u.count(x))
            {
                puts("0");
                continue;
            }
            if(p==u.end()) ans=y;
            else ans=y-(p->second);
            printf("%d
",ans);
            l[y]=x;
            u[x]=y-ans;
        }
        else
        {
            int ans=0;
            p=l.lower_bound(y);
            if(l.count(y))
            {
                puts("0");
                continue;
            }
            if(p==l.end()) ans=x;
            else ans=x-(p->second);
            printf("%d
",ans);
            u[x]=y;
            l[y]=x-ans;
        }
    }
    return 0;
}
View Code
原文地址:https://www.cnblogs.com/CJLHY/p/7225837.html