20160602常规赛总结

来源:互联网 发布:windows如何隐藏分区 编辑:程序博客网 时间:2024/05/18 01:19

Task1蛮有趣
Task2暴力dp==听老师讲了什么前缀和愣是没想通暴力的dp为什么要前缀和。。如果有前缀和我的dp就是O(n)了。。
Task3有一些问题
比如为什么关于开关问题同一个区间不会反转两次,虽然理由很有道理,但是我理解不通。。智商不够。。
那么以后只好记结论了
最后一题放一下题目讲一下思路。

图染色

Description

给定一个n个点,m条边的无向图。每条边都有一种颜色,’R’或者’B’;
每次染色可以选择一个点,把与这个相连的边的颜色都翻转。
求最少选择几个点进行染色,使得所有边的颜色最后都相同!

Solution
这个标点有点鬼。。
反正大概知道是开关问题了,那就很简单了。
首先枚举每个联通块的颜色。
并查集搞一下就差不多了。
怎么都觉得自己是第一次敲影子并查集。

[源代码]:

#include<iostream>#include<stdio.h>#include<string.h>#include<algorithm>#include<vector>using namespace std;#define pb push_back#define vec vector<int>const int M=4e5+5;struct node{int to;bool c;};vector<node>G[M];vec Nod;int n,m,fa[M],cnt[M];bool mark[M];inline void rd(int &a){    a=0;char c;    while(c=getchar(),!isdigit(c));    do a=a*10+(c^48);        while(c=getchar(),isdigit(c));}inline int find(int x){return fa[x]==x?x:fa[x]=find(fa[x]);}inline void Min(int &a,int b){if(a==-1||a>b)a=b;}void dfs(int v,const bool clr){    mark[v]=1;    Nod.pb(v);    for(int i=0;i<G[v].size();++i){        node u=G[v][i];        if(u.c==clr){            int f1=find(v),f2=find(u.to);            if(f1!=f2){                fa[f2]=f1;                cnt[f1]+=cnt[f2];            }            f1=find(v+n),f2=find(u.to+n);            if(f1^f2){                fa[f2]=f1;                cnt[f1]+=cnt[f2];            }        }        else{            int f1=find(v),f2=find(u.to+n);            if(f1!=f2){                fa[f2]=f1;                cnt[f1]+=cnt[f2];            }            f1=find(v+n),f2=find(u.to);            if(f1!=f2){                fa[f2]=f1;                cnt[f1]+=cnt[f2];            }        }        if(!mark[u.to])dfs(u.to,clr);    }}int main(){    int size = 256 << 20; // 256MB    char *p = (char*)malloc(size) + size;    __asm__("movl %0, %%esp\n" :: "r"(p));    cin>>n>>m;    char s[2];    for(int i=1,a,b,c;i<=m;++i){        rd(a),rd(b);scanf("%s",s);c=s[0]=='B';        G[a].pb((node){b,(bool)c}),G[b].pb((node){a,(bool)c});    }    int ans1=0,ans2=0;    for(int i=1;i<=n;++i)fa[i]=i,fa[i+n]=n+i,cnt[i]=1;    for(int i=1;i<=n;++i)        if(!mark[i]){            Nod.clear();            int res1=-1;            dfs(i,0);            int ct=0;            for(int j=0;j<Nod.size();++j){                if(Nod[j]==fa[Nod[j]])++ct;                if(Nod[j]+n==fa[Nod[j]]+n)++ct;            }            if(ct==1)res1=M;            else{                for(int j=0;j<Nod.size();++j){                    int v=Nod[j];                    if(fa[v]==v)Min(res1,cnt[v]);                    if(fa[v+n]==v+n)Min(res1,cnt[v+n]);                    fa[v]=v,fa[v+n]=v+n;                    cnt[v]=1,cnt[v+n]=0;                    mark[v]=0;                }            }            Nod.clear();            dfs(i,1);            int res2=-1;            ct=0;            for(int j=0;j<Nod.size();++j){                if(Nod[j]==fa[Nod[j]])++ct;                if(Nod[j]+n==fa[Nod[j]]+n)++ct;            }            if(ct==1)res2=M;            else{                for(int j=0;j<Nod.size();++j){                    int v=Nod[j];                    if(fa[v]==v)Min(res2,cnt[v]);                    if(fa[v+n]==n+v)Min(res2,cnt[v+n]);                }            }            ans1+=res1;            ans2+=res2;        }    cout<<min(ans1,ans2)<<endl;    return 0;}

代码略长,略丑。。但是思路很简单咯。

0 0