[POI2010]GIL-Guilds
比较显然。只要我们保证对于每一个节点都是由颜色不同的点转移过来即可。只需进行一次 dfs
,时间复杂度 O(n)
。
[POI2005]SKA-Piggy Banks
不难发现每个点都有且仅有一个出边,所以这个图只能是若干个 环+单链 组成。用并查集数一下联通块个数即可。
[POI2008]PLA-Postering
首先考虑高度单调递增的情况。可以一层一层的覆盖。
然后考虑有凸起部分的情况。可以发现必须花费一个代价横着涂,用单调栈维护,每次弹出元素时 ans++
,最后把栈中元素个数加上即可。时间复杂度 O(n)
。
[POI2013]LAN-Colorful Chain
运用 莫队+桶 思想统计一下颜色出现次数即可。时间复杂度 O(n)
。
[POI2012]TOU-Tour de Byteotia
首先把两个节点编号 >k
的点加入进去,然后缩点。然后把剩下的边加进去,此时如果形成环就一定包含 <=k
的节点,可以用并查集统计答案。
[POI2013]BAJ-Bytecomputer
线性动态 dp
。分 -1
/0
/1
讨论转移即可。
代码:https://www.luogu.com.cn/record/48375712
[POI2013]TAK-Taxis
贪心结论题。
首先注意到,一定存在一个 X[i]
满足 X[i]>=A-B
。考虑枚举 i
,然后贪心的从大到小枚举即可。时间复杂度 O(n^2)
。
不难想到 X[i]
的函数图象是这样的:
应取第一个 X[i]>=A-B
。然后枚举即可,时间复杂度 O(n)
。
考虑反证法。假设存在 j
满足 X[j]>X[i]
,且 X[j]
作为最后一辆。此时假若交换 X[i]
和 X[j]
的位置,车子走的距离会更远,同时能够到达 A
点。证毕。
综上,我们有两种贪心方案:
- 从大到小选取
- 选取
X[i]
作为最后一辆车,其余从大到小枚举。
时间复杂度 O(n)
。
代码:https://www.luogu.com.cn/record/53348652
[POI 2019] Pomniejszenie
贪心+大模拟。
首先想到从大到小枚举第一个不同的位数,这样可以保证数最大。
可以预处理 A[i]
表示前 i
个数不同的个数。第 i
位数比 b
小的条件是:l<=k&&k<=r
,其中 l=A[i-1]+(a[i]>=b[i])
, r=A[i-1]+(a[i]!=0||b[i]!=1)+n-i
。对于 i
后面的数就很好讨论了。
代码:https://www.luogu.com.cn/record/53169249
[POI2012]ODL-Distance
考点:阶梯 nim
博弈。
模型:有 n
堆石子,每次从 i
堆选出若干个移动到 i-1
堆,当然石子个数 >=0
。结论:等价于奇数位位置上的 nim
博弈。
证明:先考虑奇数位上的 nim
结果。假设 nim
游戏先手必胜,那么先手肯定优先玩 nim
游戏;如果后手试图破坏局面,将某个偶位置上的若干石子移动到了左边的奇位置 i
上,那么先手可以将这若干个刚移到 i
的石子继续移动到 i-1
即左边的偶位置上,对 Nim
局面依然没有任何影响。
现在考虑这道题。想到令 c[i]=a[i]-a[i-1], c[i]>=0
。那么对于一次操作 c[i]-=x ,c[i+1]+=x , x>=0
。倒着做 nim
即可。
[POI2011] LIZ-Lollipop
常见 trick
题。首先找到最大的 sum[i]<=k
,然后一波判断即可。理清思路了就不难,轻松 + 愉快。这里不用考虑移动成空集的情况,因为移走的位置都补上来了。
#include<bits/stdc++.h>
#define INF 0x3f3f3f3f
using namespace std;
const int mx=1e6+5;
int n,m,b[mx],sum[mx];
set<int> s;
char a[mx];
int main() {
scanf("%d%d%s",&n,&m,a+1);
for(int i=1;i<=n;i++) {
b[i]=(a[i]=='T')?2:1;
sum[i]=sum[i-1]+b[i];
if(b[i]==1) s.insert(i);
}
for(int i=1;i<=m;i++) {
int x; scanf("%d",&x);
if(x==1) {
if(s.size()) printf("%d %d\n",*s.begin(),*s.begin());
else printf("NIE\n");
}
else {
int l=1,r=n,res=0;
while(l<=r) {
int mid=l+r>>1;
if(sum[mid]<=x) res=mid,l=mid+1;
else r=mid-1;
}
if(sum[res]==x) {
printf("1 %d\n",res);
}
else {
auto it=s.upper_bound(res),it2=s.lower_bound(1);
if(sum[n]<x||it2==s.end()||it==s.end()&&n-res<*it2) {
printf("NIE\n");
}
else {
if(it==s.end()) {
printf("%d %d\n",*it2+1,res+*it2);
}
else {
if(*it-res<=*it2) {
printf("%d %d\n",*it-res,*it);
}
else {
printf("%d %d\n",*it2+1,res+*it2);
}
}
}
}
}
}
}