比较好想的一道题,直接用队列滑窗,因为扫一遍往队列里加东西时,改变的只有一个值,开桶储存好就行了!

#include<bits/stdc++.h>
using namespace std; int n, k, r; inline int min(int a, int b) {
return a > b ? b : a;
} inline int max(int a, int b) {
return a > b ? a : b;
} int sum[], q[], cnt[], vis[], ned[];
int a[]; int main() {
freopen("drop.in", "r", stdin);
freopen("drop.out", "w", stdout);
int T;
scanf("%d", &T);
while(T --) {
memset(sum, , sizeof(sum));
memset(q, , sizeof(q));
memset(cnt, , sizeof(cnt));
memset(vis, , sizeof(vis));
memset(ned, , sizeof(ned));
scanf("%d%d%d", &n, &k, &r);
int tot = , fl = ;
for(int i = ; i <= n; i ++) {
scanf("%d", &a[i]);
sum[a[i]] ++;
}
for(int i = ; i <= r; i ++) {
int b, p;
scanf("%d%d", &b, &p);
if(!vis[b]) vis[b] = , tot ++;
if(sum[b] < p) {
fl = ; break;
}
ned[b] = max(ned[b], p);
}
if(fl) {
printf("DESTROY ALL\n"); continue;
}
int ans = 0x3f3f3f3f;
int h = , t = , now = ;
for(int i = ; i <= n; i ++) {
if(vis[a[i]]) {
q[++t] = i; cnt[a[i]] ++; if(cnt[a[i]] == ned[a[i]]) now ++;
}
while(now == tot && h < t) {
ans = min(ans, q[t] - q[h+] + );
cnt[a[q[h+]]] --;
if(cnt[a[q[h+]]] < ned[a[q[h+]]]) now --;
h ++;
}
}
printf("%d\n", ans);
}
return ;
}

考场上想到$2-sat$但是忘得差不多了,打死都理不清楚关系。

这道题算是$2-sat$板子题了,主要是如何判断的思想。

首先题目条件疯狂暗示,但是和$2-sat$的一般理解方式不同。题目上给的约束条件我们按$2-sat$让他们避免相连,实际上就是题目中的防守文明,我们要摧毁文明,实际上是要让防守文明失效。即至少有一个点和它的负点相互相通。因为$n$很小就可以用两次$dfs$实现,然后就是分类讨论来判断该加几条边。

1、假如初始连边中就有某一个点对正负点相互连接,答案就是0.

2、假如一个点对中正点连向负点:

   1)如果负点可以连向另一点对的正点,根据$2-sat$的对称行,另一点对的负点一定可以连向当前点对的正点,所以我们只用加条件$(i,j)$,就是在$-i$和$-j$之间连了一条边,使i点对相互连通。

   2)如果负点没有连向任意点对的正点,那么一定无解,输出$No Way$。

3、假如一个点对中负点连向正点:

那么只用加一个条件$(i,i)$,相当于在$i$和$-i$间连边即可。

4、假如点对之间没有连边:

1)将2、3结合,但是必须满足2的条件,这样加两条边即可。

2)没有2的条件,就无法加边,输出$No Way$。

#include<bits/stdc++.h>
using namespace std; struct Node {
int u, v, nex;
Node(int u = , int v = , int nex = ) :
u(u), v(v), nex(nex) { }
} Edge[]; int h[], stot;
void add(int u, int v) {
Edge[++stot] = Node(u, v, h[u]);
h[u] = stot;
} int vis[];
void dfs(int u) {
vis[u] = ;
for(int i = h[u]; i; i = Edge[i].nex) {
int v = Edge[i].v;
if(vis[v]) continue;
dfs(v);
}
} int n, m;
int main() {
freopen("god.in", "r", stdin);
freopen("god.out", "w", stdout);
int T;
scanf("%d", &T);
while(T --) {
memset(h, , sizeof(h));
stot = ;
scanf("%d%d", &n, &m);
for(int i = ; i <= m ; i++) {
int x, y;
scanf("%d%d", &x, &y);
if(x > || y < ) swap(x, y);
if(x > && y > ) {
add(x, y + n);
add(y, x + n);
}
if(x < && y < ) {
add(-x + n, -y);
add(-y + n, -x);
}
if(x < && y > ) {
add(-x + n, y + n);
add(y, -x);
}
}
int tag1 = , tag2 = , tag0 = ;
for(int i = ; i <= n; i ++) {
memset(vis, , sizeof(vis));
dfs(i);
int fl = ;
if(vis[i + n]) {
memset(vis, , sizeof(vis));
dfs(i + n);
fl = ;
if(vis[i]) {
tag0 = ; break;
}
for(int j = ; j <= n; j ++) {
if(j != i && vis[j]) {
tag1 = ; break;
}
}
}
memset(vis, , sizeof(vis));
dfs(i + n);
if(vis[i]) {
tag1 = ;
} else if(!fl) {
for(int j = ; j <= n; j ++) {
if(j != i && vis[j]) {
tag2 = ; break;
}
}
}
}
if(tag0) printf("0\n");
else if(tag1) printf("1\n");
else if(tag2) printf("2\n");
else printf("No Way\n");
} return ;
}

一道好题。(但是现在不想写题解了aaaa)

所以复制题解~

60分:

考虑这样一个贪心:
先从左往右扫,如果某一时刻不满足要求,则需要删除前面中某一个支持对方的人。我们贪心地选择删除当前时刻访问的人(肯定是支持对方),然后继续往后扫。
然后再从右往左扫,作相同的操作。
直观地理解是这样的:我们尽量删除靠右的人,使得从右往左扫时少删除一些人。
可以采用交换论证法证明这贪心是对的。

80-100:

首先我们可以发现从左往右扫完,从右往左扫的这个过程可以不用实现出来。只需要求出右端点开始的最小后缀和的相反数即可。
然后我们发现,如果两个询问区间拥有相同的左端点,则只需要作一次从左往右扫的工作。这使我们想到要离线化解决问题。

我们将询问按左端点排序,按照左端点从大到小的顺序求解询问。
如果已知从 i 开始向右扫需要删除那些结点,则从 i-1 开始向右扫需要删除那些结点可以快速求出。具体来说,如果i-1是支持者,则左数第一个被删除的结点与它抵消;如果i-1是反对者,则加入被删除的结点里。
该过程可以用栈维护。

通过在栈里面二分,我们可以知道区间[l, r]在从左往右扫时需要删除的结点数量。
现在问题就是求解以 r 为端点的最小后缀和。
这个东西可以用块状数组O(sqrt(N))维护(这就是80%算法的由来),更好的方法应该是用线段树O(log(N))维护
于是该题就在O((N+Q)logN)的时间复杂度内解决了。

#include<bits/stdc++.h>
using namespace std; struct Tree {
int mi, sum;
} TR[*]; int n, m;
char s[]; void update(int nd) {
TR[nd].mi = min(TR[nd << | ].mi, TR[nd << ].mi + TR[nd << | ].sum);
TR[nd].sum = TR[nd << ].sum + TR[nd << | ].sum;
} void build(int nd, int l, int r) {
if(l == r) {
TR[nd].mi = TR[nd].sum = ;
return ;
}
int mid = (l + r) >> ;
build(nd << , l, mid);
build(nd << , mid + , r);
update(nd);
} void modify(int nd, int l, int r, int pos, int d) {
if(l == r) {
TR[nd].sum = d;
TR[nd].mi = d;
return ;
}
int mid = (l + r) >> ;
if(pos <= mid) modify(nd << , l, mid, pos, d);
else modify(nd << | , mid + , r, pos, d);
update(nd);
} Tree query(int nd, int l, int r, int pos) {
if(l == r) return TR[nd];
int mid = (l + r) >> ;
if(pos <= mid) return query(nd << , l, mid, pos);
else {
Tree res = query(nd << | , mid + , r, pos);
res.mi = min(res.mi, res.sum + TR[nd << ].mi);
res.sum = res.sum + TR[nd << ].sum;
return res;
}
} vector < pair < int , int > > qus[];
int tp = , stk[], ans[]; int find(int pos) {
int l = , r = tp, an = tp + ;
while(l <= r) {
int mid = (l + r) >> ;
if(stk[mid] > pos) l = mid + ;
else an = mid, r = mid - ;
}
return an;
} int main() {
freopen("sworder.in", "r", stdin);
freopen("sworder.out", "w", stdout);
scanf("%d", &n);
scanf("%s", s + );
scanf("%d", &m);
for(int i = ; i <= m; i ++) {
int l, r;
scanf("%d%d", &l, &r);
qus[l].push_back(make_pair(r, i));
}
build(, , n);
for(int i = n; i >= ; i --) {
if(s[i] == 'C') stk[++tp] = i;
else {
if(tp) {
modify(, , n, stk[tp], -);
stk[tp--] = ;
}
modify(, , n, i, );
}
for(int j = ; j < qus[i].size(); j ++) {
int pos = qus[i][j].first;
int tmp = find(pos);
ans[qus[i][j].second] = (tp - tmp + ) - min(, query(, , n, pos).mi);
}
}
for(int i = ; i <= m; i ++) printf("%d\n", ans[i]);
return ;
}

【10.7校内测试】【队列滑窗】【2-sat】【贪心+栈二分+线段树(noip模拟好题)】【生日祭!】的更多相关文章

  1. 【10.11校内测试】【优先队列(反悔贪心)】【莫队】【stl的应用??离线处理+二分】

    上次做过类似的题,原来这道还要简单些?? 上次那道题是每天可以同时买进卖出,所以用两个优先队列,一个存买进,一个存卖出(供反悔的队列). 这道题实际上用一个就够了???但是不好理解!! 所以我还是用了 ...

  2. [CSP-S模拟测试]:platform(后缀数组+二分+线段树)

    题目传送门 题目描述 走过奈何桥有一个名叫望乡台的土台,望乡台有个名曰孟婆的老妇人在卖孟婆汤.一生爱恨情仇,一世浮沉得失,都可以随这碗孟婆汤遗忘得干干净净.现在有$n$碗孟婆汤摆成一排,汤的品种不超过 ...

  3. 【10.17校内测试】【二进制数位DP】【博弈论/预处理】【玄学(?)DP】

    Solution 几乎是秒想到的水题叻! 异或很容易想到每一位单独做贡献,所以我们需要统计的是区间内每一位上做的贡献,就是统计区间内每一位是1的数的数量. 所以就写数位dp辣!(昨天才做了数字统计不要 ...

  4. 【10.5校内测试】【DP】【概率】

    转移都很明显的一道DP题.按照不优化的思路,定义状态$dp[i][j][0/1]$表示吃到第$i$天,当前胃容量为$j$,前一天吃(1)或不吃(0)时能够得到的最大价值. 因为有一个两天不吃可以复原容 ...

  5. 【10.31校内测试】【组合数学】【记忆化搜索/DP】【多起点多终点二进制拆位Spfa】

    Solution 注意取模!!! Code #include<bits/stdc++.h> #define mod 1000000007 #define LL long long usin ...

  6. 【10.29校内测试】【线段树】【DP】【二进制Trie树求最小值最大】

    Solution 标程太暴力惹QAQ 相当于是26棵线段树的说QAQ 不过我写了另一种写法,从大到小枚举每一个字母,标记字典序在这个字母之上的位置为1,每次都建一棵线段树,维护1的数量,即区间和. 修 ...

  7. 【10.26校内测试】【状压?DP】【最小生成树?搜索?】

    Solution 据说正解DP30行??? 然后写了100行的状压DP?? 疯狂特判,一算极限时间复杂度过不了aaa!! 然而还是过了....QAQ 所以我定的状态是待转移的位置的前三位,用6位二进制 ...

  8. 【10.6校内测试】【小模拟】【hash+线段树维护覆盖序列】

    一开始看到题就果断跳到T2了!!没想到T2才是个大坑,浪费了两个小时QAQ!! 就是一道小模拟,它怎么说就怎么走就好了! 为什么要用这么多感叹号!!因为统计答案要边走边统计!!如果每个数据都扫一遍20 ...

  9. 【10.4校内测试】【轮廓线DP】【中国剩余定理】【Trie树+博弈】

    考场上几乎是一看就看出来轮廓线叻...可是调了两个小时打死也过不了手出样例!std发下来一对,特判对的啊,转移对的啊,$dp$数组竟然没有取max!!! 某位考生当场死亡. 结果下午又请了诸位dala ...

随机推荐

  1. JDK1.8源码TreeMap

    基于红黑树(Red-Black tree)的 NavigableMap 实现:键的排序由构造方法决定:自然排序,Comparator排序:非线程安全(仅改变与现有键关联的值不是结构上的修改):线程安全 ...

  2. PlantUML——4.实例演示1

    给自己发消息 @startuml Alice -> Alice : This is a signal to self.\nIt also demonstrates \nmultiline tex ...

  3. 程序设计分层思想和DAO设计模式的开发

    无论是一个应用程序项目还是一个Web项目,我们都可以按照分层思想进行程序设计.对于分层,当下最流行划分方式是:表现层+控制层+业务层+数据层.其中,业务层和数据层被统称为后台业务层,而表现层和控制层属 ...

  4. 洛谷P1266速度限制

    传送门啦 看起来是一个最短路问题,但是引入了速度限制,就要写一下二维最短路了. $ dis[i][j] $ :表示到i这个点,速度为j的最短时间. #include <iostream> ...

  5. 网络协议之UDP

    前言 TCP协议在不可靠的网络环境上提供了可靠的通信通道,隐藏了大量的底层细节,使应用程序更加简洁.但有些应用并不需要这么高的可靠性,并不需要按序交付,而且TCP为了提高可靠性也增加了延时,在某些对延 ...

  6. T-SQL创建前删除已存在存储过程

    --判断是否存在addOneArticle这个存储过程 if Exists(select name from sysobjects where NAME = 'addOneArticle' and t ...

  7. MyBatis的动态插入语句(经常报‘无效的列类型’)

    最近在工作中经常遇到一个情况:通过mybatis的标签执行插入语句,当表中字段比较多的时候,需要全部插入,而有时候的需求是只插入其中几个字段,但是会报错. 原来的语句,必须把所有字段都Set值. &l ...

  8. IIS部署asp.net MVC 出现错误 403.14-Forbidden解决办法

    可能性一: <system.webServer>   <validationvalidateIntegratedModeConfiguration="false" ...

  9. 基于CommonsChunkPlugin,webpack打包优化

    前段时间一直在基于webpack进行前端资源包的瘦身.在项目中基于路由进行代码分离,http://www.cnblogs.com/legu/p/7251562.html.但是打包的文件还是很大,特别是 ...

  10. 【51nod】1149 Pi的递推式

    题解 我们把这个函数的递归形式画成一张图,会发现答案是到每个出度为0的点的路径的方案数 这个可以用组合数算 记录一下P[i]为i减几次PI减到4以内 如果P[i + 1] > P[i],那么转向 ...