传送门

C. Ivan the Fool and the Probability Theory

题意:

给出一个\(n*m\)的方格,现在要给方格中的元素黑白染色,要求任一颜色最多有一个颜色相同的格子和它相邻。问多少种方案。

思路:

  • 观察到若第一行含有两个相同的颜色相邻,那么之后所有格子的状态都可以确定;
  • 若第一行不含有两个相同的颜色相邻,那么下一行至多有两种状态。

根据这两个观察,可以发现状态数其实不多,我们再推导一下:

  • 对于第一种情况,假设第一个格子为白色,第二个格子有黑白两种选择:若选择白,则第三个格子只有一种选择;否则第三个格子有两种选择;
  • 对于第二种情况,第一行不妨为黑白交错,那么若第二行也为黑白交错,第三行只有一种情况;否则第三行能有两种情况。

发现这两个有类似之处,并且都是一到二或者二到一,在纸上画一下可以发现随着行数/列数的增加,状态数为斐波那契数。

所以这个题求一下斐波那契数就行了。

答案为\(2*(F_m-1+F_n)\)

Code
#include <bits/stdc++.h>
#define MP make_pair
#define fi first
#define se second
#define sz(x) (int)(x).size()
#define all(x) (x).begin(), (x).end()
// #define Local
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
const int N = 1e5 + 5, MOD = 1e9 + 7; int n, m; void run() {
int ans = 0;
int pre = 1, now = 1;
for(int i = 2; i <= m; i++) {
int tmp = now;
now = (pre + now) % MOD;
pre = tmp;
}
ans = 2ll * (now - 1) % MOD;
pre = 1, now = 1;
for(int i = 2; i <= n; i++) {
int tmp = now;
now = (pre + now) % MOD;
pre = tmp;
}
ans = (ans + 2ll * now) % MOD;
cout << ans << '\n';
} int main() {
ios::sync_with_stdio(false);
cin.tie(0); cout.tie(0);
cout << fixed << setprecision(20);
#ifdef Local
freopen("../input.in", "r", stdin);
freopen("../output.out", "w", stdout);
#endif
while(cin >> n >> m) run();
return 0;
}

D2. The World Is Just a Programming Task (Hard Version)

题意:

给出一个括号序列,现在可以选择两个括号进行交换,使得合法的\(shift\)最多。

定义\(shift_i\)合法:将序列后\(i\)个放到前面后,形成的新的括号序列合法,\(1\leq i<n\)。

思路:

这个题有很重要的两个观察,首先令\((\)为\(1\),\()\)为\(-1\),\(sum_i\)为序列的前缀和,并且\(min=min\{sum_i\}\)。我们先将\(sum_n\not ={0}\)的情况排除,然后:

  • 观察1: 若\(sum_i=min\),那么\(shift_{n-i}\)一定为一个合法序列;
  • 观察2: \(shift\)具有传递性,多次\(shift\)可以合并为一次\(shift\)。

观察\(2\)比较好理解(就是不好注意到这一个性质QAQ),观察\(1\)之所以正确,是因为因为\(sum_i\)为最小值,那么对于\(j>i,sum_j-sum_i\geq 0\)并且有\(sum_j-sum_i=-min\)。那么我们将后面这部分放到前面,首先前面这一块始终合法,然后后面最小值为\(min\),也不能使序列非法。

因为观察2,我们可以任选一个合法\(shift\)并且得到新序列,之后我们的任务就是使得新序列的\(sum'_i=min'=0\)的个数最多(观察1+观察2)。

然后还有一个比较重要的地方,就是我们改变一对括号序列,会使得一段数中的前缀值减少\(2\)。

那么我们首先统计新序列中\(sum'_i=0\)的个数,然后还要统计连续段中\(sum'_i=2\)的个数,因为将其减少\(2\)之后会得到\(0\);

之后再统计一下连续段中\(sum'_i=1\)的个数即可,减去之后最小值会为\(-1\)。

对于\(sum'_i>2\)的其余位置,就算减去\(2\)也不会对答案尝试贡献。

刚才说的一段数,是这样一段数:\(sum_i=1,sum_j=1,i< k\leq j,sum_j\geq 2\)这样的一段数(以第一种情况举例),此时我们选择交换\(i+1,j\)这两个位置,如果我们不改变\(j\)这个位置的括号,那么就会多出一个\()\)就不合法了。

说了这么多,本质还是贪心。。

还是代码清楚点:

Code
#include <bits/stdc++.h>
#define MP make_pair
#define fi first
#define se second
#define sz(x) (int)(x).size()
#define all(x) (x).begin(), (x).end()
// #define Local
#ifdef Local
#define dbg(args...) do { cout << #args << " -> "; err(args); } while (0)
void err() { std::cout << '\n'; }
template<typename T, typename...Args>
void err(T a, Args...args) { std::cout << a << ' '; err(args...); }
#else
#define dbg(...)
#endif
void pt() {std::cout << '\n'; }
template<typename T, typename...Args>
void pt(T a, Args...args) {std::cout << a << ' '; pt(args...); }
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
//head
const int N = 300005; int n;
char s[N], t[N];
int sum[N]; void run() {
cin >> (s + 1);
for(int i = 1; i <= n; i++) {
sum[i] = sum[i - 1];
sum[i] += (s[i] == '(' ? 1 : -1);
}
if(sum[n] != 0) {
pt(0); pt(1, 1);
return;
}
int Min = *min_element(sum + 1, sum + n + 1);
int all = 0, shift;
for(int i = 1; i <= n; i++) {
if(sum[i] == Min) shift = i;
}
for(int i = shift + 1; i <= n; i++) {
t[i - shift] = s[i];
}
for(int i = 1; i <= shift; i++) {
t[n - shift + i] = s[i];
}
t[n + 1] = '\0';
strcpy(s + 1, t + 1);
auto srcp = [&](int p) {
return (p + shift - 1) % n + 1;
};
// dbg(n, shift, srcp(2));
for(int i = 1; i <= n; i++) {
sum[i] = sum[i - 1];
sum[i] += (s[i] == '(' ? 1 : -1);
if(sum[i] == 0) ++all;
}
vector <int> ans = {all, 1, 1};
int last = 0, cnt = 0;
//Case 1: min = 0
for(int i = 1; i <= n; i++) {
if(sum[i] == 2) ++cnt;
else if(sum[i] <= 1) {
ans = max(ans, std::vector<int>{all + cnt, srcp(last + 1), srcp(i)});
last = i;
cnt = 0;
}
}
dbg(ans[0], ans[1], ans[2]);
//Case 2: min = -1
last = cnt = 0;
for(int i = 1; i <= n; i++) {
if(sum[i] == 1) ++cnt;
else if(sum[i] <= 0) {
ans = max(ans, std::vector<int>{cnt, srcp(last + 1), srcp(i)});
last = i;
cnt = 0;
}
}
pt(ans[0]);
pt(ans[1], ans[2]);
} int main() {
ios::sync_with_stdio(false);
cin.tie(0); cout.tie(0);
cout << fixed << setprecision(20);
#ifdef Local
freopen("../input.in", "r", stdin);
freopen("../output.out", "w", stdout);
#endif
while(cin >> n) run();
return 0;
}

F. Catowice City

题意:

给出一个二分图,保证\(i\)和\(i'\)有边相连。

输出一个最大独立集的方案。

思路:

  • 显然,我们选择的两个点之间没有边相连;
  • 我们可以将\(i\)到\(i'\)的边看作从右向左,其余边为从左向右,那么我们求出每一个强连通分量。
  • 若强连通分量个数为\(1\),根据题意不存在解;否则,不同强连通分量之间不存在边相连(若存在,则不满足“极大子图”)。那么直接按照强连通分量来划分了。

代码如下:

Code
#include <bits/stdc++.h>
#define MP make_pair
#define fi first
#define se second
#define sz(x) (int)(x).size()
#define all(x) (x).begin(), (x).end()
// #define Local
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
const int N = 1e6 + 5; int n, m; stack <int> s;
int T, num;
int col[N], dfn[N], low[N];
std::vector<int> scc[N], g[N];
void Tarjan(int u){
dfn[u] = low[u] = ++T;
s.push(u);
for(auto v : g[u]){
if(!dfn[v]){
Tarjan(v);
low[u] = min(low[u], low[v]);
}else if(!col[v]){
low[u] = min(low[u], dfn[v]);
}
}
if(low[u] == dfn[u]){
num++; int now;
do{
now = s.top(); s.pop();
col[now] = num;
scc[num].push_back(now);
}while(!s.empty() && now!=u);
}
} void init() {
for(int i = 1; i <= n; i++) {
scc[i].clear();
g[i].clear();
col[i] = dfn[i] = 0;
}
num = T = 0;
} void run() {
cin >> n >> m;
init();
for(int i = 1; i <= m; i++) {
int u, v; cin >> u >> v;
g[u].push_back(v);
}
for(int i = 1; i <= n; i++) {
if(!dfn[i]) {
Tarjan(i);
}
}
if(n == 1 || num == 1) {
cout << "No" << '\n';
return;
}
std::vector<int> ans[2];
ans[0] = scc[1];
for(int i = 2; i <= num; i++) {
for(auto it : scc[i]) ans[1].push_back(it);
}
cout << "Yes" << '\n';
cout << sz(ans[0]) << ' ' << sz(ans[1]) << '\n';
for(auto it : ans[0]) cout << it << ' ';
cout << '\n';
for(auto it : ans[1]) cout << it << ' ';
cout << '\n';
} int main() {
ios::sync_with_stdio(false);
cin.tie(0); cout.tie(0);
cout << fixed << setprecision(20);
#ifdef Local
freopen("../input.in", "r", stdin);
freopen("../output.out", "w", stdout);
#endif
int T; cin >> T;
while(T--) run();
return 0;
}

Codeforces Round #594 (Div. 2)的更多相关文章

  1. Codeforces Round #594 (Div. 1) D. Catowice City 图论

    D. Catowice City In the Catowice city next weekend the cat contest will be held. However, the jury m ...

  2. Codeforces Round #594 (Div. 1) C. Queue in the Train 模拟

    C. Queue in the Train There are

  3. Codeforces Round #594 (Div. 1) D2. The World Is Just a Programming Task (Hard Version) 括号序列 思维

    D2. The World Is Just a Programming Task (Hard Version) This is a harder version of the problem. In ...

  4. Codeforces Round #594 (Div. 2) B. Grow The Tree 水题

    B. Grow The Tree Gardener Alexey teaches competitive programming to high school students. To congrat ...

  5. Codeforces Round #594 (Div. 2) A. Integer Points 水题

    A. Integer Points DLS and JLS are bored with a Math lesson. In order to entertain themselves, DLS to ...

  6. Codeforces Round #594 (Div. 1) A. Ivan the Fool and the Probability Theory 动态规划

    A. Ivan the Fool and the Probability Theory Recently Ivan the Fool decided to become smarter and stu ...

  7. Codeforces Round #594 (Div. 1)

    Preface 这场CF真是细节多的爆炸,B,C,F都是大细节题,每道题都写了好久的说 CSP前的打的最后一场比赛了吧,瞬间凉意满满 希望CSP可以狗住冬令营啊(再狗不住真没了) A. Ivan th ...

  8. B. Grow The Tree Codeforces Round #594 (Div. 2)

    Gardener Alexey teaches competitive programming to high school students. To congratulate Alexey on t ...

  9. Codeforces Round #594 (Div. 2)(A/B/C)

    A. Integer PointsDescription DLS and JLS are bored with a Math lesson. In order to entertain themsel ...

随机推荐

  1. Linux日志中如何查找关键字及其前后的信息

    在日常工作中,我们经常需要查看日志,比如可以通过 tail 命令实时查看日志,也可以通过 cat 等命令查看日志信息. 但现在我们要讨论的是,如何从日志中通过关键字过滤出我们想要的内容,方法有多种,今 ...

  2. .NET Core 使用HMAC算法

    一. HMAC 简介 通过哈希算法,我们可以验证一段数据是否有效,方法就是对比该数据的哈希值,例如,判断用户口令是否正确,我们用保存在数据库中的password_md5对比计算md5(password ...

  3. vue element之axios下载文件(后端Python)

    axios 接受文件流,需要设置 {responseType:'arraybuffer'} axios.post( apiUrl, formdata, {responseType:'arraybuff ...

  4. ling to sql创建临时变量 let的使用

    使用let赋值给临时变量 var dailys = from f in _postgreDbContext.draws let temp = f.review_time.Value.Date wher ...

  5. Netfilter,获取http明文用户名和密码

    目录 Netfilter简介 实验-target端 内核模块的操作 初始化netfilter 解析http包,获取用户名和密码 实验-hack端 遇到的问题 @ Netfilter简介 Netfilt ...

  6. Python中列表乘法需注意的问题/

    前几天看到一个关于Python的面试题 lst = [1, 2, [3]] lst1 = lst * 2  #  [1, 2, [3], 1, 2, [3]] lst1[2].append(4)  # ...

  7. C# Winform更换Webbrowse为WebKit

    本人第一次发表博文,内容不精也不是很有水平,请大家多多包涵~ 说到Webbrowser,可能大家都用过这个控件,它默认使用的是旧版本IE内核. 这就导致了一些问题,比如JS的加载不正确,这个问题就足够 ...

  8. (理论知识+HTML+CSS+JavaScript)

    今天分享的面试题的答案不确保一定正确,如有错误或有更好的解法,大家可以留言分享你的答案.我在留言区等你更好的答案. 一.理论基础知识部分 1.1.讲讲输入完网址按下回车,到看到网页这个过程中发生了什么 ...

  9. springboot 多环境

    springboot 多环境 --spring.profiles.active=dev 查看 Ioc 容器 PostProcessorRegistrationDelegate

  10. IT兄弟连 HTML5教程 HTML5文字版面和编辑标签 小结及试题

    小结 HTML标签包含结构标签和基础标签,基础标签是在页面制作最常使用的一些标签.基础标签包含标题标签(<h1>~<h6>).换行标签(<br>).段落标签(< ...