简单:
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<queue>
#include<cstdio>
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<algorithm>
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
那么就转化成网络流问题了。