Codeforces Round #469 (Div. 2)

A 送分 拼手速

快速读懂题意后

#include <iostream>
#include <cmath>
using namespace std;

int main()
{
    int a,b,c;
    cin>>a>>b>>c;
    int d = abs(a-b);
    int x = min(a,b);
    int y = max(a,b);
    int ans;
    if(c<=d)//双手人少于两种人的差
        ans = x+c;
    else
        ans = y+(c-d)/2;
    cout<<2*ans<<endl;
}

B 基本送分,也拼手速

双指针比较,老是因为i和j的自增写错,
记住一点,i,j是指向当前值,还是之后的值,
我这里i,j都是指向当前值,即用到在自增;
这样不容易出错

#include <iostream>
#include <cmath>
using namespace std;
const int N=1e5+10;
int A[N];
int B[N];
int n,m;
int main()
{
    cin>>n>>m;
    for(int i=0;i<n;i++)cin>>A[i];
    for(int j=0;j<m;j++)cin>>B[j];
    int i,j;
    i=j=0;
    int s1,s2;
    s1=A[i];
    s2=B[j];
    int ans=0;
    while(i<n && j<m)
    {
        if(s1==s2)
        {
            ans++;
            i++;j++;
            s1=A[i];
            s2=B[j];
        }
        else if(s1<s2)
        {
            i++;
            s1+=A[i];
        }
        else
        {
            j++;
            s2+=B[j];
        }
    }
    if(i!=n||j!=m)//跳出循环再判断是否要+1
    {
        ans++;
    }
    cout<<ans<<endl;
}

C 思路挺简单的一道题,代码不是很好写罢了

- Zabre 469 div2 C

比赛的时候没看清楚题目,单个的0,和00 都是合法的,所以末尾剩下的0就不用考虑匹配了,这样就很简单
只要考虑1,充分利用现有的0,把1都给放了,(按照题意0101的规则放置)
这样考虑,输出-1的情况只有两个

  • 没有0来放后面的1
  • 最后放完了还有1在最后面
#include <iostream>
#include <cstdio>
#include <cstring>
#include <vector>
#include <list>
#include <queue>
/*
#include <cmath>
#include <cstdlib>
#include <algorithm>
*/
#define mem(x) memset(x,0,sizeof(x))


using namespace std;
const int N=2e5+10;
int queue_tail[N];//保存每一个子序列的尾部
vector<int> T[N];//保存子序列的下标
int main()
{
    string s;
    cin>>s;
    int len=0;
    queue<int> zero,one;//暴力搜索能放的位置会TLE,把能放的位置放在队列里
    int top=0;//每个多出来的0都放在top位置,以便继续放后面的1;
    bool fg=true;
    mem(queue_tail);
    for(int i=0;i<s.length();i++)
    {
        char tp = s[i];
        if(tp=='0')
        {
            int loc;
            if(zero.empty())
            {
                loc=top++;
            }
            else
            {
                loc = zero.front();
                zero.pop();
            }
            T[loc].push_back(i+1);
            queue_tail[loc]=0;
            one.push(loc);
        }
        else
        {
            int loc;
            if(one.empty())
            {
                fg=false;
                break;
            }
            else
            {
                loc = one.front();
                one.pop();
            }
            T[loc].push_back(i+1);
            queue_tail[loc]=1;
            zero.push(loc);
        }
    }
    for(int i=0;i<top;i++)
    {
        if(queue_tail[i]==1)
        {
            fg=false;
            break;
        }
    }
    if(fg)
    {
        int i=0;
        printf("%d\n",top);
        int len;
        while(true)
        {
            len = T[i].size();
            if(len==0)break;
            printf("%d ",len);
            for(int j=0;j<len;j++)
            {
                printf("%d%s",T[i][j],j==len-1?"\n":" ");
            }
            i++;
        }
    }
    else
    {
        cout<<-1<<endl;
    }
    return 0;
}

E. Data Center Maintenance

  • 题意:

    题目很长读了半天,就是几个个东西

    1. 有n个数据中心
    2. 有m个客户
    3. 每天有h小时
    4. 数据中心在某几个小时点会进行一小时的维护
    5. 每个客户能从两个不同的数据中心获取数据
    6. 问题的前提是任一客户在任意时间都至少有一个数据中心不在维护
    7. 问题的输出就是,关键 在保证6的情况下,取一个最小子集,将他们延后一个小时
    8. 试想,如果原来满足6,那么把所有维护机都往后延后一个小时,还是能保证6,所以每个问题都至少有一个解,就是全部拿来实验

尝试解题

数据n,m,h的范围都是1e5;
nlogn的复杂度才能保证不TLE

对于第二个样例(我们吧数据中心的下标列在客户数据后面)

4 5 4
2 1 0 3

4 3 0 3
3 2 0 1
1 2 2 1
1 4 2 3
1 3 2 0

不难看出来,如果一个客户的两个客户中心相差一个小时,那早更新的那个如果加入实验,必然导致另外一个也加入实验,对于一个二元关系我们可以建立一个图来解决
例如第2个客户,3 2
那么数据中心3连一条有向弧到2;表示,如果数据中心3,如果加入试验,那么2也必须加入试验。
那么问题就转换成为
求一个最小的连通块
接下来代码就很好写了
写着发现没这么简单
应该要先将这个有向图缩点 成为一个DAG
然后 取 缩点后的所有出度为0的点 中 点的数目最小的那个连通块,才能满足题意。
缩点代码参考我的另外一篇blog
本题代码

比赛当时实在不想看题目,
第二天也花了好长时间才看懂题目。虽然结合样例不难看懂,但是还是看了好长时间。
看懂题目了的话思路就很清晰,既然是一个二元约束关系,转换成图论来写就行了。
然后第一发WA了,坑点是,建图的时候,如果只有两个数据中心,并且时间分别是,0和1
那么对于一个客户01来说可以牵两条边即 0->1 ,1->0;
我写的时候没注意,如果真真的比赛,我想很难发现这个问题吧。
谁能想到是建图建错了。。。。

抽象一下就是,对于一个客户来讲,可能产生两个约束关系;

值得一提的是,这里n比较大。所以不能用邻接矩阵来去掉重复边。
不过好在,m对边的限制,不会让复杂度爆炸,依旧用vector数组的邻接表来表示图;
tarjan算法要记录每个强连通分量的number,以及每个点所属的连通分量。
在缩点和,最后输出那个scc的所有的点的时候要用到。

#include <cstring>
#include <cstdio>
#include <vector>
#include <iostream>
#define mem(x) memset(x,0,sizeof(x))

using namespace std;

int n,m,h;
const int N=1e5+10;
int A[N];
int ans[N];
int k;

int Low[N],DFN[N],Stack[N],Belong[N];
int Index,top;
int scc;
bool Instack[N];
int num[N];
int outdegree[N];

vector<int> G[N];

void init()
{
    for(int i=1;i<=n;i++)
        G[i].clear();
    mem(outdegree);
}

void Tanjan(int u)
{
    int v;
    Low[u]= DFN[u] =++Index;
    Stack[top++]=u;
    Instack[u]=true;
    for(int i=0;i<G[u].size();i++)
    {
        v=G[u][i];
        if(!DFN[v])
        {
            Tanjan(v);
            if(Low[u]>Low[v])Low[u]=Low[v];
        }
        else if(Instack[v] && Low[u]>DFN[v])
            Low[u]=DFN[v];
    }
    if(Low[u]==DFN[u])
    {
        scc++;
        do
        {
            v=Stack[--top];
            Instack[v]=false;
            Belong[v]=scc;
            num[scc]++;
        }while(v!=u);
    }
}

void solve(int n)
{
    mem(DFN);
    mem(Instack);
    mem(num);
    Index = scc = top = 0;
    for(int i=1;i<=n;i++)
        if(!DFN[i])
            Tanjan(i);
}


int main()
{
    //freopen("../in.txt","r",stdin);
    while(cin>>n>>m>>h)
    {
        init();
        for(int i=1;i<=n;i++)
            cin>>A[i];
        for(int i=0;i<m;i++)
        {
            int a,b;
            cin>>a>>b;
            int aa,bb;
            aa=A[a];
            bb=A[b];
            if((aa-bb)==1)
            {
                G[b].push_back(a);
            }
            else if((bb-aa)==1)
            {
                G[a].push_back(b);
            }
            if((aa-bb)==(h-1))
            {
                G[a].push_back(b);
            }
            else if((bb-aa)==(h-1))
            {
                G[b].push_back(a);
            }
        }
        solve(n);
        for(int u=1;u<=n;u++)
        {
            int v;
            int uu,vv;
            uu=Belong[u];
            for(int j=0;j<G[u].size();j++)
            {
                v=G[u][j];
                vv=Belong[v];
                if(uu!=vv)
                {
                    outdegree[uu]++;
                }
            }
        }

        int k,cnt;
        cnt=n+1;
        for(int i=1;i<=scc;i++)
        {

            if(outdegree[i]==0 && num[i]<cnt)
            {
                cnt=num[i];
                k=i;
            }
        }
        int tt=0;
        for(int i=1;i<=n;i++)
            if(Belong[i]==k)
                ans[tt++]=i;
        cout<<cnt<<endl;
        for(int i=0;i<tt;i++)
            cout<<ans[i]<<(i==tt-1?"\n":" ");
    }
    return 0;
}
posted @ 2018-03-10 19:24  enlong  阅读(135)  评论(0编辑  收藏  举报