建议大家去 UOJ 交题
题目描述
有 场游戏和三种车,每个游戏可以选择用一种车,每个游戏可能要求不能使用某种车,也可能没有要求。
给出 个要求,表示如果第
个游戏用了
车,那么第
个游戏要用
车。求一种合法方案。
,没有要求的游戏个数
不超过
。
题解
前置小知识:2-SAT
链接
建图
首先考虑如果没有没有要求的游戏个数的话是不是一个经典的 2-SAT 问题。
注意到三个字母的状态其实是假的,每个游戏其实只有两个状态。
然后我们就可以对于每一个限制 分类讨论了:
游戏不能选
直接忽略掉就好了,对答案无影响。可选
,
游戏不能选
意思就是不能选择
,(不存在对应的
)在图上对应着边
可选
,
可选
就是限制当时
,直接连边
。
发现没有要求的游戏个数很小,选择 枚举,时间复杂度
小优化
然后交到 BZOJ,惊奇的发现:
然后你按照博主的指引交到了 UOJ,发现:
仔细一看 原来被人叉了。有人构造了一组非常大的无解数据,这样会跑满,运算量大概是 。并且 UOJ 限时
直接 T 了。
我们猜想满足条件的 应该是很多的,于是我们枚举改为随机,然后卡时,然后加上 Ofast,用上关流的 cin,找个吉时就过了!

代码
/*
* Author: RainAir
* Time: 2019-10-12 09:06:50
*/
#pragma GCC optimize(2)
#pragma GCC optimize(3)
#pragma GCC optimize("Ofast")
#include <algorithm>
#include <iostream>
#include <cstring>
#include <climits>
#include <cstdlib>
#include <cstdio>
#include <bitset>
#include <vector>
#include <cmath>
#include <ctime>
#include <queue>
#include <stack>
#include <map>
#include <set>
#define fi first
#define se second
#define U unsigned
#define P std::pair
#define LL long long
#define pb push_back
#define MP std::make_pair
#define all(x) x.begin(),x.end()
#define CLR(i,a) memset(i,a,sizeof(i))
#define FOR(i,a,b) for(register int i = a;i <= b;++i)
#define ROF(i,a,b) for(register int i = a;i >= b;--i)
#define DEBUG(x) std::cerr << #x << '=' << x << std::endl
const int MAXN = 5e4 + 5;
const int MAXM = 1e5 + 5;
struct Edge{
int to,nxt;
}e[MAXM<<1];
int head[MAXM],cnt;
char str[MAXN];
clock_t start;
std::vector<int> ps;
int n,d,m;
// a,b 和其他字符
inline void add(int u,int v){
e[++cnt] = (Edge){v,head[u]};head[u] = cnt;
}
struct Query{
int i,j;char hi,hj;
}q[MAXM];
char t0[MAXN],t1[MAXN],ch[23];
int dfn[MAXM],low[MAXM],col[MAXM];
int st[MAXM],tp,tot;
bool ins[MAXM];
inline void dfs(int v){
static int ts = 0;
dfn[v] = low[v] = ++ts;ins[v] = true;st[++tp] = v;
for(int i = head[v];i;i = e[i].nxt){
if(!dfn[e[i].to]){
dfs(e[i].to);low[v] = std::min(low[v],low[e[i].to]);
}
else if(ins[e[i].to]) low[v] = std::min(low[v],dfn[e[i].to]);
}
if(low[v] == dfn[v]){
int t = -1;++tot;
do{
t = st[tp--];
col[t] = tot;
ins[t] = false;
}while(t != v);
}
}
inline void clear(){
CLR(head,0);CLR(dfn,0);CLR(ins,0);CLR(col,0);
tp = tot = cnt = 0;
}
inline void Solve(){
// puts("NEW BEGINNING");
FOR(i,1,n){
if(str[i] == 'A') t0[i] = 'B',t1[i] = 'C';
else if(str[i] == 'B') t0[i] = 'A',t1[i] = 'C';
else t0[i] = 'A',t1[i] = 'B';
}
// FOR(i,1,n) printf("%c %c\n",t0[i],t1[i]);
FOR(i,1,m){
int u = q[i].i,v = q[i].j;
if(t0[u] == q[i].hi){
if(str[v] == q[i].hj) add(u,u+n);
else{
if(t0[v] == q[i].hj) add(u,v),add(v+n,u+n);
if(t1[v] == q[i].hj) add(u,v+n),add(v,u+n);
}
}
if(t1[u] == q[i].hi){
if(str[v] == q[i].hj) add(u+n,u);
else{
if(t0[v] == q[i].hj) add(u+n,v),add(v+n,u);
if(t1[v] == q[i].hj) add(u+n,v+n),add(v,u);
}
}
}
FOR(i,1,2*n) if(!dfn[i]) dfs(i);
FOR(i,1,n) if(col[i] == col[n+i]){
clear();return;
}
// num[i] > num[i+1]
// col[i] < col[n+i]
FOR(i,1,n) putchar(col[i] < col[n+i] ? t0[i] : t1[i]);exit(0);
// 缩点后编号小的拓扑序大
}
inline double now(){
clock_t end = clock();
return 1.0*(end-start)/CLOCKS_PER_SEC;
}
int G[MAXN];
int main(){
std::ios::sync_with_stdio(false);
srand(time(NULL));
start = clock();
// scanf("%d%d",&n,&d);
std::cin >> n >> d;
std::cin >> (str+1);
// scanf("%s",str+1);
FOR(i,1,n) str[i] -= 32;
FOR(i,1,n) if(str[i] == 'X') ps.pb(i);
// scanf("%d",&m);
std::cin >> m;
FOR(i,1,m){
// scanf("%d",&q[i].i);scanf("%s",ch);
std::cin >> q[i].i >> ch;
q[i].hi = ch[0];
// scanf("%d",&q[i].j);scanf("%s",ch);
std::cin >> q[i].j >> ch;
q[i].hj = ch[0];
}
std::vector<int> G;
FOR(S,0,(1<<d)-1) G.pb(S);
std::random_shuffle(all(G));
FOR(S,0,(1<<d)-1){
FOR(i,0,d-1) str[ps[i]] = (G[S]&(1<<i)) ? 'A' : 'B';
Solve();
if(now() > 1.983) break;
}
puts("-1");
return 0;
} 
京公网安备 11010502036488号