传送门

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. 利用Fiddler对Jmeter的请求进行抓包

    前言 有时候,为了得到更详细的请求结果,我们可能需要使用Fiddler结合Jmeter来抓包分析,从而更好的辅助测试. 遇到的问题 这里以一个获取学生信息的接口为例进行说明. 当我在Jmeter里按接 ...

  2. js 淡入淡出的tab选项卡

    代码如下 <!DOCTYPE html> <html> <head lang="en"> <meta charset="UTF- ...

  3. Create a Report at Runtime 在运行时创建报表

    In this lesson, you will learn how to create reports at runtime. A report showing a list of Tasks wi ...

  4. 编译原理之LL(1)文法的判断,递归下降分析程序

    1. 文法 G(S): (1)S -> AB (2)A ->Da|ε (3)B -> cC (4)C -> aADC |ε (5)D -> b|ε 验证文法 G(S)是不 ...

  5. 【Spring Cloud】Spring Cloud Config 实现分布式配置中心

    Spring Cloud Config 实现分布式配置中心 一.分布式配置中心 分布式系统中,往往拥有大量的服务应用,而每个应用程序都需要有对应的配置文件来协助完成服务环境初始化.运行.因此生产了大量 ...

  6. SQL Server获取索引创建时间&重建时间&重组时间

    之前写过一篇博客"SQL Server中是否可以准确获取最后一次索引重建的时间?",里面主要讲述了三个问题:我们能否找到索引的创建时间?最后一次索引重建(Index Rebuild ...

  7. centos安装Redis和设置远程访问

    记录下步骤以后用到时翻一翻. 一.下载官方的文件包和编译 在centos下载依赖库: yum install gcc tcl 在redis官网的下载页面,这里可以选择离线包或在线下载. 我选择在线的, ...

  8. 常用的git和repo命令

    首先下图是git的流程图 相关概念 svn与git命令的对比 git常用命令 git log // 查看当前库的git log信息 git status ./ // 查看当前库的状态 git diff ...

  9. mysql分组报错Expression #1 of SELECT list is not in GROUP BY clause and contains nonaggregated column

    环境:Server version: 5.7.27-0 ubuntu 18.04.1 (Ubuntu) 执行分组语句:select * from pet group by owner;时报错: mys ...

  10. 批量群发,营销必备!Python代码实现自动发送邮件!

    在运维开发中,使用 Python 发送邮件是一个非常常见的应用场景.今天一起来探讨一下,GitHub 的大牛门是如何使用 Python 封装发送邮件代码的. 一般发邮件方法 SMTP是发送邮件的协议, ...