POI乱刷计划题解

简单:

bzoj 3524: [Poi2014]Couriers

区间第mid大……

bzoj 1113: [Poi2008]海报PLA

单调栈裸题。

bzoj 1131: [POI2008]Sta

树形dp裸题。

bzoj 1115: [POI2009]石子游戏Kam

差分后就是经典阶梯博弈。

bzoj 1116: [POI2008]CLO

容易发现一个连通块有环就一定可以,并查集直接上就好了。

bzoj 2212: [Poi2011]Tree Rotations

线段树合并
在合并两颗子树时顺便统计下代价即可。

bzoj 2084: [Poi2010]Antisymmetry

将回文自动机改改即可。

bzoj 1106: [POI2007]立方体大作战tet

显然直接模拟是最优的。
树状数组加速即可。

中等:

bzoj 1098: [POI2007]办公楼biu

其实还是简单的,只是我太菜了……
容易想到 n2 n 2 的暴力,建补图+并查集。
但是实际上很多边都没用,所以用链表维护剩下的点,bfs即可。
code:

#include
#include
#include
#include
#include
#include
using namespace std;
int n,m;
int next[100010],pre[100010];
struct node{
    int y,next;
}a[4000010];int last[100010],len=0;
int d[100010];
void ins(int x,int y)
{
    a[++len].y=y;
    a[len].next=last[x];last[x]=len;
}
void del(int x)
{
    d[x]=1;
    int t=pre[x];
    next[t]=next[x];
    pre[next[x]]=t;
}
int num[100010],cnt=0;
int vis[100010],tim=1;
queue<int> q;
void bfs(int x)
{
    q.push(x);
    while(!q.empty())
    {
        num[cnt]++;tim++;
        x=q.front();q.pop();
        for(int i=last[x];i;i=a[i].next) vis[a[i].y]=tim;
        for(int i=next[0];i<=n;i=next[i])
            if(vis[i]!=tim&&!d[i])
                del(i),q.push(i);
    }
}
int main()
{
    scanf("%d %d",&n,&m);
    for(int i=0;i<=n;i++) next[i]=i+1;
    for(int i=1;i<=n+1;i++) pre[i]=i-1;
    for(int i=1;i<=m;i++)
    {
        int x,y;scanf("%d %d",&x,&y);
        ins(x,y);ins(y,x);
    }
    for(int i=next[0];i<=n;i=next[0])
        del(i),cnt++,bfs(i);
    printf("%d\n",cnt);
    sort(num+1,num+cnt+1);
    for(int i=1;i<=cnt;i++) printf("%d ",num[i]);
}

bzoj 1132: [POI2008]Tro

枚举+排序+叉积。
式子化开可以发现能用前缀和优化。

困难:

bzoj 2095: [Poi2010]Bridges

显然是二分答案+check
那么就是要判断混合图的欧拉回路(同时存在有向边和无向边)
考虑有向图欧拉回路的存在条件:联通且每个点的入度=出度
对于混合图,先对无向边对边定个向,假如存在点的度数是奇数,就一定不合法。
如果将一条边反向,会使链接的两个点的入度数出度差 2/+2 − 2 / + 2
那么就转化成网络流问题了。

你可能感兴趣的:(其他)