codeforces Round #310(Div.1) 题解

嘴巴选手真爽,一不用打代码二不用掉Rating三还可以打杂。。。。

感觉这套题不难,但是被出题人出瞎了。。。

555A. Case of Matryoshkas

题目大意:给定n个大小从1到n的套娃,初始套成k坨,每次你可以选择两个操作:

1.选择一个不在任何其他套娃里的套娃,将里面的套娃取出来(要求原先里面有套娃)

2.选择一个不再任何其他套娃里的套娃,将一个套娃塞进去(要求原先里面没有套娃)

求将所有套娃合并的最小操作次数

如果一个套娃x初始在最里面,或者满足大小为1...x?1的套娃都在它里面,那么这个套娃可以不用拆开

将所有需要拆开的套娃拆开,然后一一合并

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define M 100100
using namespace std;
int n,m,k,cnt,ans;
int main()
{
    int i,j,x,last;
    cin>>n>>k;
    for(i=1;i<=k;i++)
    {
        bool flag=false;
        scanf("%d",&m);
        for(j=1;j<=m;j++)
        {
            scanf("%d",&x);
            if(j>1)
                ++ans;
            if(flag&&x==last+1)
                --ans;
            else
                ++cnt,flag=false;
            if(x==1)
                flag=true;
            last=x;
        }
    }
    cout<<ans+cnt-1<<endl;
    return 0;
}

555B. Case of Fugitive

题目大意:给定n个岛,第i个岛可以用一个区间[li,ri]表示,满足对于任意1≤i<n有ri<li+1

现在需要将每两个相邻的岛之间架一座桥,桥的长度需要在[li+1?ri,ri+1?li]之间

给定m块木板,问是否能完成任务

问题可以简化为给定n?1个区间和m个点问是否存在一个匹配满足每个点都在对应区间内且所有区间都被匹配上

将区间按左端点从大到小排序,依次扫描

每次扫描到一个区间,将所有大于等于区间左端点的点都扔进set,然后取走所有小于等于区间右端点的点中最大的那个,不存在则无解

#include <set>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define M 200200
using namespace std;
struct Interval{
    long long l,r,id;
    bool operator < (const Interval &i) const
    {
        return l < i.l ;
    }
}intervals[M];
int n,m,ans[M];
set< pair<long long,int> > s;
pair<long long,int> points[M];
int main()
{
    int i,j;
    long long _l,_r,l,r;
    cin>>n>>m>>_l>>_r;n--;
    for(i=1;i<=n;i++)
    {
        scanf("%I64d%I64d",&l,&r);
        intervals[i].l=l-_r;
        intervals[i].r=r-_l;
        intervals[i].id=i;
        _l=l;_r=r;
    }
    for(i=1;i<=m;i++)
    {
        scanf("%I64d",&points[i].first);
        points[i].second=i;
    }
    sort(intervals+1,intervals+n+1);
    sort(points+1,points+m+1);
    for(j=m,i=n;i;i--)
    {
        for(;j&&points[j].first>=intervals[i].l;j--)
            s.insert(points[j]);
        set< pair<long long,int> >::iterator it=s.upper_bound(make_pair(intervals[i].r+1,0));
        if(it==s.begin())
            return puts("No"),0;
        --it;ans[intervals[i].id]=it->second;s.erase(it);
    }
    puts("Yes");
    for(i=1;i<=n;i++)
        printf("%d%c",ans[i],i==n?‘\n‘:‘ ‘);
    return 0;
}

555C. Case of Chocolate

题目大意:给定一个n?n的巧克力,初始啃掉副对角线右下方的区域,然后每次选择副对角线上的一个位置,然后选择一个方向(上/左),一路啃下去,直到啃到一个空的位置为止,输出啃掉的长度

每啃一次会把当前啃到的块分成至多两小块

当前剩下的每一块巧克力可以用一个四元组(l,r,left_bound,up_bound)表示,其中l和r表示副对角线上的区间,left_bound表示左边界,up_bound表示上边界

每次啃的时候去set上找啃到哪块即可

#include <set>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
struct abcd{
    int l,r;
    int left_bound,up_bound;
    abcd() {}
    abcd(int _,int __,int ___,int ____):
        l(_),r(__),left_bound(___),up_bound(____) {}
    bool operator < (const abcd &a) const
    {
        return r < a.r ;
    }
};
int n,q;
set<int> v;
set<abcd> s;
int main()
{
    int i,x,y;
    char p[10];
    cin>>n>>q;
    s.insert(abcd(1,n,1,1));
    for(i=1;i<=q;i++)
    {
        scanf("%d%d%s",&y,&x,p);
        if(v.find(y)!=v.end())
        {
            puts("0");
            continue;
        }
        v.insert(y);
        set<abcd>::iterator it=s.lower_bound(abcd(0,y,0,0));
        abcd temp=*it;s.erase(it);
        if(p[0]==‘U‘)
        {
            printf("%d\n",x-temp.up_bound+1);
            s.insert(abcd(temp.l,y-1,temp.left_bound,temp.up_bound));
            s.insert(abcd(y+1,temp.r,y+1,temp.up_bound));
        }
        else
        {
            printf("%d\n",y-temp.left_bound+1);
            s.insert(abcd(temp.l,y-1,temp.left_bound,x+1));
            s.insert(abcd(y+1,temp.r,temp.left_bound,temp.up_bound));
        }
    }
    return 0;
}

555D. Case of a Top Secret

题目大意:给定n个挂点,m个重锤,第i个重锤初始挂在第ai个挂点上,挂绳长度为leni,初始向右摆动,刮到一个重锤后会折返,问最后挂在哪个重锤上

每次二分找位置,记录路径,如果是A?A?A就输出答案,如果是A?B?A就取模,这样不超过log2len次挂绳的长度就会变为0

复杂度O(m?log2n?log2len)

注意初始给出的挂点不一定按顺序,注意挂点的标号不是排序后的标号。。。

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define M 200200
using namespace std;

int n,m;
int a[M],b[M],id[M];
//id[i]=j表示排序后的第i个是排序前的第j个

int stack[1001001],top;

int main()
{
    int i,pos,len;
    cin>>n>>m;
    for(i=1;i<=n;i++)
        scanf("%d",&a[i]);
    memcpy(b+1,a+1,sizeof(a[0])*n);
    sort(a+1,a+n+1);
    for(i=1;i<=n;i++)
        id[lower_bound(a+1,a+n+1,b[i])-a]=i;

    for(i=1;i<=m;i++)
    {
        scanf("%d%d",&pos,&len);
        pos=lower_bound(a+1,a+n+1,b[pos])-a;
        stack[top=1]=pos;
        while(1)
        {
            if( top>=3 && stack[top]==stack[top-1] && stack[top]==stack[top-2] )
            {
                printf("%d\n",id[stack[top]]);
                break;
            }
            if( top>=3 && stack[top]==stack[top-2] )
                len%=abs(a[stack[top]]-a[stack[top-1]])<<1;
            int next_pos;
            if(top&1)
                next_pos=upper_bound(a+1,a+n+1,a[pos]+len)-a-1;
            else
                next_pos=lower_bound(a+1,a+n+1,a[pos]-len)-a;
            len-=abs(a[pos]-a[next_pos]);
            pos=next_pos;stack[++top]=pos;
        }
    }
    return 0;
}

555E. Case of Computer Network

题目大意:给定一张无向图,要求有向化,使得有向化之后si可以到达ti

一个边双有向化之后可以变成一个强连通分量

缩边双后剩下一座森林,每条边只能被指定一个方向,DFS一遍判断即可

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define M 200200
using namespace std;

struct edge{
    int x,y;
}edges[M];
struct abcd{
    int to,next;
}table[M<<1];
int head[M],tot=1;

int n,m,q,cnt;

int belong[M],dpt[M],fa[M][18];

int mark1[M],mark2[M];

void Add(int x,int y)
{
    table[++tot].to=y;
    table[tot].next=head[x];
    head[x]=tot;
}
void Tarjan(int x,int from)
{
    static int dpt[M],low[M],T;
    static int stack[M],top;
    int i;
    dpt[x]=low[x]=++T;
    stack[++top]=x;
    for(i=head[x];i;i=table[i].next)
        if(i^from^1)
        {
            if(dpt[table[i].to])
                low[x]=min(low[x],dpt[table[i].to]);
            else
                Tarjan(table[i].to,i),low[x]=min(low[x],low[table[i].to]);
        }
    if(dpt[x]==low[x])
    {
        int t;++cnt;
        do{
            t=stack[top--];
            belong[t]=cnt;
        }while(t!=x);
    }
}
namespace Union_Find_Set{
    int fa[M],rank[M];
    int Find(int x)
    {
        if(!fa[x]||fa[x]==x)
            return fa[x]=x;
        return fa[x]=Find(fa[x]);
    }
    void Union(int x,int y)
    {
        x=Find(x);y=Find(y);
        if(x==y) return ;
        if(rank[x]>rank[y])
            swap(x,y);
        if(rank[x]==rank[y])
            ++rank[y];
        fa[x]=y;
    }
}
void DFS1(int x)
{
    int i;
    dpt[x]=dpt[fa[x][0]]+1;
    for(i=1;i<=17;i++)
        fa[x][i]=fa[fa[x][i-1]][i-1];
    for(i=head[x];i;i=table[i].next)
        if(table[i].to!=fa[x][0])
        {
            fa[table[i].to][0]=x;
            DFS1(table[i].to);
        }
}
int LCA(int x,int y)
{
    int j;
    if(dpt[x]<dpt[y])
        swap(x,y);
    for(j=17;~j;j--)
        if(dpt[fa[x][j]]>=dpt[y])
            x=fa[x][j];
    if(x==y) return x;
    for(j=17;~j;j--)
        if(fa[x][j]!=fa[y][j])
            x=fa[x][j],y=fa[y][j];
    return fa[x][0];
}
void DFS2(int x)
{
    int i;
    for(i=head[x];i;i=table[i].next)
        if(table[i].to!=fa[x][0])
        {
            DFS2(table[i].to);
            mark1[x]+=mark1[table[i].to];
            mark2[x]+=mark2[table[i].to];
        }
    if(mark1[x]&&mark2[x])
        exit((puts("No"),0));
}
int main()
{
    using namespace Union_Find_Set;
    int i,x,y;
    cin>>n>>m>>q;
    for(i=1;i<=m;i++)
    {
        scanf("%d%d",&x,&y);
        edges[i].x=x;
        edges[i].y=y;
        Add(x,y);Add(y,x);
    }
    for(i=1;i<=n;i++)
        if(!belong[i])
            Tarjan(i,0);
    memset(head,0,sizeof head);tot=0;
    for(i=1;i<=m;i++)
    {
        x=belong[edges[i].x];
        y=belong[edges[i].y];
        if(x!=y)
            Add(x,y),Add(y,x),Union(x,y);
    }
    for(i=1;i<=cnt;i++)
        if(i==Find(i))
            DFS1(i);
    for(i=1;i<=q;i++)
    {
        scanf("%d%d",&x,&y);
        x=belong[x];
        y=belong[y];
        if(Find(x)!=Find(y))
            return puts("No"),0;
        int lca=LCA(x,y);
        mark1[x]++;mark2[y]++;
        mark1[lca]--;mark2[lca]--;
    }
    for(i=1;i<=n;i++)
        if(i==Find(i))
            DFS2(i);
    puts("Yes");
    return 0;
}

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-08-14 04:15:33

codeforces Round #310(Div.1) 题解的相关文章

Codeforces Round #262 (Div. 2) 题解

A. Vasya and Socks time limit per test 1 second memory limit per test 256 megabytes input standard input output standard output Vasya has n pairs of socks. In the morning of each day Vasya has to put on a pair of socks before he goes to school. When

Codeforces Round #FF (Div. 2) 题解

比赛链接:http://codeforces.com/contest/447 A. DZY Loves Hash time limit per test 1 second memory limit per test 256 megabytes input standard input output standard output DZY has a hash table with p buckets, numbered from 0 to p?-?1. He wants to insert n 

贪心/思维题 Codeforces Round #310 (Div. 2) C. Case of Matryoshkas

题目传送门 1 /* 2 题意:套娃娃,可以套一个单独的娃娃,或者把最后面的娃娃取出,最后使得0-1-2-...-(n-1),问最少要几步 3 贪心/思维题:娃娃的状态:取出+套上(2),套上(1), 已套上(0),先从1开始找到已经套好的娃娃层数, 4 其他是2次操作,还要减去k-1个娃娃是只要套上就可以 5 详细解释:http://blog.csdn.net/firstlucker/article/details/46671251 6 */ 7 #include <cstdio> 8 #i

Codeforces Round #259 (Div. 2) 题解

A. Little Pony and Crystal Mine time limit per test 1 second memory limit per test 256 megabytes input standard input output standard output Twilight Sparkle once got a crystal from the Crystal Mine. A crystal of size n (n is odd; n?>?1) is an n?×?n 

找规律/贪心 Codeforces Round #310 (Div. 2) A. Case of the Zeros and Ones

题目传送门 1 /* 2 找规律/贪心:ans = n - 01匹配的总数,水 3 */ 4 #include <cstdio> 5 #include <iostream> 6 #include <algorithm> 7 #include <cstring> 8 #include <cmath> 9 using namespace std; 10 11 const int MAXN = 2e5 + 10; 12 const int INF =

Codeforces Round #177 (Div. 2) 题解

[前言]咦?现在怎么流行打CF了?于是当一帮大爷在执着的打div 1的时候,我偷偷的在刷div 2.至于怎么决定场次嘛,一般我报一个数字A,随便再拉一个人选一个数字B.然后开始做第A^B场.如果觉得机密性不高,来点取模吧.然后今天做的这场少有的AK了.(其实模拟赛只做完了4题,最后1题来不及打了) 等等,话说前面几题不用写题解了?算了,让我难得风光一下啦. [A] A. Polo the Penguin and Segments time limit per test 2 seconds mem

构造 Codeforces Round #310 (Div. 2) B. Case of Fake Numbers

题目传送门 1 /* 2 题意:n个数字转盘,刚开始每个转盘指向一个数字(0~n-1,逆时针排序),然后每一次转动,奇数的+1,偶数的-1,问多少次使第i个数字转盘指向i-1 3 构造:先求出使第1个指向0要多少步,按照这个次数之后的能否满足要求 4 题目读的好累:( 5 */ 6 #include <cstdio> 7 #include <iostream> 8 #include <algorithm> 9 #include <cstring> 10 #i

Codeforces Round #534 (Div. 2)题解

Codeforces Round #534 (Div. 2)题解 A. Splitting into digits 题目大意 将一个数字分成几部分,几部分求和既是原数,问如何分可以使得分出来的各个数之间的差值尽可能小 解题思路 将n分成n个1相加即可 AC代码 #include<cstring> #include<string> #include<iostream> #include<cstdio> using namespace std; int main

Codeforces Round #561 (Div. 2) 题解

Codeforces Round #561 (Div. 2) 题解 题目链接 A. Silent Classroom 水题. Code #include <bits/stdc++.h> using namespace std; typedef long long ll; const int N = 105; int n; char s[N], t[N]; int main() { cin >> n; for(int i = 1; i <= n; i++) { scanf(&q