机房测试10.7

题解之前

今天是三体的题目背景,比什么美好的每一天好理解多了。

水滴


难得的NOIP模拟题,滑窗解决。
也可以二分区间长度,再进行统计。

我的\(nlogn\)算法

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<ctime>
#define FN "drop"

const int maxn=2e5+5;
int dan[maxn];
int cnt[maxn];
int need[maxn];
int n,k,R;

bool check(int len) {
	memset(cnt,0,sizeof cnt);
	int res=R;
	for(int i=1;i<=len;i++) {
		cnt[dan[i]]++;
		if(cnt[dan[i]]==need[dan[i]]) --res;
		if(!res) return true;
	}
	for(int l=2,r=len+1;r<=n;l++,r++) {
		--cnt[dan[l-1]];
		if(cnt[dan[l-1]]==need[dan[l-1]]-1) ++res;
		++cnt[dan[r]];
		if(cnt[dan[r]]==need[dan[r]]) --res;
		if(!res) return true;
	}
	return false;
}

int main() {
	freopen(FN".in","r",stdin);
	freopen(FN".out","w",stdout);
	int T;scanf("%d",&T);
	while(T--) {
		memset(need,0,sizeof need);
		memset(dan,0,sizeof dan);
		scanf("%d%d%d",&n,&k,&R);
		for(int i=1;i<=n;i++) scanf("%d",dan+i);
		for(int i=1;i<=R;i++) {
			int c,num;scanf("%d%d",&c,&num);
			need[c]=num;
		}
		int l=0,r=n+1,ans=-1;
		while(l<r) {
			int mid=l+r>>1;
			if(check(mid)) {
				ans=mid;
				r=mid;
			}
			else l=mid+1;
		}
		if(!~ans) printf("DESTROY ALL\n");
		else  printf("%d\n",ans);
	}
	return 0;
}

std的O(n)算法

#include<cstdio>
#include<algorithm>
using namespace std;
const int MAXN = 200000;
int D[MAXN + 5], ned[MAXN + 5];
int tot[MAXN + 5], nw[MAXN + 5];
void solve() {
	int N, K, R;
	scanf("%d%d%d", &N, &K, &R);
	for(int i=0;i<K;i++)
		ned[i] = tot[i] = 0;
	for(int i=1;i<=N;i++) {
		scanf("%d", &D[i]);
		tot[D[i]]++;
	}
	for(int i=1;i<=R;i++) {
		int B, Q;
		scanf("%d%d", &B, &Q);
		ned[B] = Q;
	}
	for(int i=0;i<K;i++)
		if( tot[i] < ned[i] ) {
			puts("DESTROY ALL");
			return ;
		}
	int ans = N, re = R, le = 1, ri = 0;
	while( le <= N ) {
		while( ri + 1 <= N && re ) {
			nw[D[++ri]]++;
			if( nw[D[ri]] == ned[D[ri]] )
				re--;
		}
		if( !re ) ans = min(ans, ri-le+1);
		if( nw[D[le]] == ned[D[le]] ) re++;
		nw[D[le++]]--;
	}
	printf("%d\n", ans);
}
int main() {
	freopen("drop.in", "r", stdin);
	freopen("drop.out", "w", stdout);
	int T;
	scanf("%d", &T);
	for(int i=1;i<=T;i++)
		solve();
}

“神“


2-SAT裸题?

一眼看出来2-SAT,边都连好了,写不来算法。

太菜了。

#include<cstdio>
#include<algorithm>
using namespace std;
const int MAXN = 5000;
struct edge{
	int to;
	edge *nxt;
}edges[2*MAXN + 5], *adj[MAXN + 5], *ecnt=&edges[0];
void addedge(int u, int v) {
	edge *p = (++ecnt);
	p->to = v, p->nxt = adj[u], adj[u] = p;
}
void init() {
	ecnt = &edges[0];
	for(int i=0;i<=MAXN;i++)
		adj[i] = NULL;
}
bool vis[MAXN + 5];
void dfs(int x) {
	vis[x] = true;
	for(edge *p=adj[x];p!=NULL;p=p->nxt)
		if( !vis[p->to] ) dfs(p->to);
}
void solve() {
	init(); int N, M;
	scanf("%d%d", &N, &M);
	for(int i=1;i<=M;i++) {
		int u, v;
		scanf("%d%d", &u, &v);
		if( u < 0 )
			u = (-u-1)<<1|1;
		else u = (u-1)<<1;
		if( v < 0 )
			v = (-v-1)<<1|1;
		else v = (v-1)<<1;
		addedge(u, v^1);
		addedge(v, u^1);
	}
	int ans = 3;
	for(int i=0;i<N;i++) {
		bool f1 = false, f2 = false, f3 = false;
		for(int j=0;j<(N<<1);j++)
			vis[j] = false;
		dfs(i<<1);
		f1 = vis[i<<1|1];
		for(int j=0;j<(N<<1);j++)
			vis[j] = false;
		dfs(i<<1|1);
		f2 = vis[i<<1];
		for(int j=0;j<N;j++)
			f3 = f3 || vis[j<<1];
		if( f1 && f2 ) ans = min(ans, 0);
		else if( f2 ) ans = min(ans, 1);
		else if( f3 ) {
			if( f1 ) ans = min(ans, 1);
			else ans = min(ans, 2);
		}
	}
	if( ans == 3 ) puts("No Way");
	else printf("%d\n", ans);
}
int main() {
	freopen("god.in", "r", stdin);
	freopen("god.out", "w", stdout);
	int T;
	scanf("%d", &T);
	for(int i=1;i<=T;i++)
		solve();
}

执剑人


贪心+数据结构。

只会贪心,于是只有60分。

用后缀和来选出枪毙名单。
用栈存从一边开始的枪毙名单,线段树从另外一边开始操作。

#include<cstdio>
#include<vector>
#include<algorithm>
using namespace std;
const int INF = (1<<30);
const int MAXN = 500000;
struct query{
	int ri, ind;
	query(int _r, int _i):ri(_r), ind(_i){}
};
vector<query>qry[MAXN + 5];
char str[MAXN + 5];
int stk[MAXN + 5], ans[MAXN + 5], top;
struct node{
	int mss, sum;
	int le, ri;
}tree[4*MAXN + 5];
void PushUp(int x) {
	tree[x].mss = min(tree[x<<1|1].mss, tree[x<<1].mss + tree[x<<1|1].sum);
	tree[x].sum = tree[x<<1].sum + tree[x<<1|1].sum;
}
void Build(int x, int l, int r) {
	tree[x].le = l, tree[x].ri = r;
	if( l == r ) {
		tree[x].mss = tree[x].sum = 0;
		return ;
	}
	int mid = (l + r) >> 1;
	Build(x<<1, l, mid);
	Build(x<<1|1, mid+1, r);
	PushUp(x);
}
void Modify(int x, int pos, int key) {
	if( pos > tree[x].ri || pos < tree[x].le )
		return ;
	if( tree[x].le == tree[x].ri ) {
		tree[x].sum = tree[x].mss = key;
		return ;
	}
	Modify(x<<1, pos, key);
	Modify(x<<1|1, pos, key);
	PushUp(x);
}
node Query(int x, int pos) {
	if( tree[x].ri <= pos )
		return tree[x];
	int mid = (tree[x].le + tree[x].ri) >> 1;
	if( pos <= mid )
		return Query(x<<1, pos);
	else {
		node ret = Query(x<<1|1, pos);
		ret.mss = min(ret.mss, ret.sum + tree[x<<1].mss);
		ret.sum = ret.sum + tree[x<<1].sum;
		return ret;
	}
}
inline int Read() {
	char ch = getchar(); int x = 0, f = 1;
	while( (ch > '9' || ch < '0') && ch != '-' ) ch = getchar();
	if( ch == '-' ) f = -1, ch = getchar();
	while( '0' <= ch && ch <= '9' )
		x = 10*x + ch-'0', ch = getchar();
	return x * f;
}
int main() {
	freopen("sworder.in", "r", stdin);
	freopen("sworder.out", "w", stdout);
	int N, Q;
	scanf("%d%s%d", &N, str+1, &Q);
	for(int i=1;i<=Q;i++) {
		int l, r;
		l = Read(), r = Read();
		qry[l].push_back(query(r, i));
	}
	Build(1, 1, N); top = N+1;
	for(int i=N;i>=1;i--) {
		if( str[i] == 'C' )
			stk[--top] = i;
		else {
			if( top != N+1 ) {
				Modify(1, stk[top], -1);
				stk[top++] = 0;
			}
			Modify(1, i, 1);
		}
		for(int j=0;j<qry[i].size();j++) {
			int p = upper_bound(stk+top, stk+N+1, qry[i][j].ri) - stk;
			ans[qry[i][j].ind] = (p-top) - min(0, Query(1, qry[i][j].ri).mss);
		}
	}
	for(int i=1;i<=Q;i++)
		printf("%d\n", ans[i]);
}

于是今天愉快地拿到了大众分数。

posted @ 2018-10-07 17:09  LoLiK  阅读(110)  评论(0编辑  收藏  举报