Educational Codeforces Round 71 (Rated for Div. 2)
A.There Are Two Types Of Burgers
签到。
B.Square Filling
签到
C.Gas Pipeline
每个位置只有“高、低”两种状态,所以直接根据条件来\(dp\)即可。
Code
#include <bits/stdc++.h>
#define MP make_pair
#define INF 0x3f3f3f3f3f3f3f3f
using namespace std;
typedef long long ll;
const int N = 2e5 + 5;
ll n, a, b;
int T;
char s[N];
ll dp[N][2];
int main() {
ios::sync_with_stdio(false); cin.tie(0);
cin >> T;
while(T--) {
cin >> n >> a >> b;
cin >> s;
for(int i = 0; i <= n; i++) dp[i][0] = dp[i][1] = INF;
dp[0][0] = b;
for(int i = 1; i <= n; i++) {
if(s[i - 1] == '1' || s[i] == '1') dp[i][1] = min(dp[i - 1][0] + 2 * (a + b), dp[i - 1][1] + a + 2 * b);
else {
dp[i][0] = min(dp[i - 1][1] + 2 * a + b, dp[i - 1][0] + a + b);
dp[i][1] = min(dp[i - 1][1] + a + 2 * b, dp[i - 1][0] + 2 * (a + b));
}
}
cout << dp[n][0] << '\n';
}
return 0;
}
### D.Number Of Permutations
题意:
给出\(n\)个二元组\((a_i,b_i)\),定义一个坏的序列为:序列中按第一关键字或者按第二关键字是非递减的。
相反,好的序列的定义就与之相反。
现在问有多少种打乱方式,能够得到好的序列。
思路:
- 考虑直接来求,发现过于复杂。
- 所以考虑利用容斥的思想来做,先分别求出按第一关键字、第二关键字非递减的方案数,最后求出同时非递减的方案数,加加减减即可。
- 同时非递减这种情况怎么处理呢?
- 观察可以发现此时\(a_i,b_i\)分别非递减,所以我们就暴力扫一遍找共同部分就行了。
- 那一个非递减,另一个不是呢?这种我们上面会计算到,此时答案为1,包含在上面计算中了。
注意还有特殊情况的判断:
Code
#include <bits/stdc++.h>
#define MP make_pair
#define INF 0x3f3f3f3f3f3f3f3f
#define fi first
#define se second
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
const int N = 3e5 + 5, MOD = 998244353;
int n;
pii p[N];
ll fac[N];
ll gao1() {
ll res = 1;
for(int i = 1, j; i <= n; i = j) {
for(j = i; j <= n + 1; j++) {
if(p[i].fi != p[j].fi) break;
}
int cnt = 1;
for(int k = i + 1; k < j; k++) {
if(p[k].se == p[k - 1].se) ++cnt;
else {
res = res * fac[cnt] % MOD;
cnt = 1;
}
}
res = res * fac[cnt] % MOD;
}
return res;
}
ll gao2() {
ll res = 1;
for(int i = 1, j; i <= n; i = j) {
for(j = i; j <= n + 1; j++) {
if(p[i].se != p[j].se) break;
}
int cnt = 1;
for(int k = i + 1; k < j; k++) {
if(p[k].fi == p[k - 1].fi) ++cnt;
else {
res = res * fac[cnt] % MOD;
cnt = 1;
}
}
res = res * fac[cnt] % MOD;
}
return res;
}
int main() {
ios::sync_with_stdio(false); cin.tie(0);
cin >> n;
for(int i = 1; i <= n; i++) {
cin >> p[i].fi >> p[i].se;
}
sort(p + 1, p + n + 1);
fac[0] = 1;
for(int i = 1; i <= n; i++) fac[i] = fac[i - 1] * i % MOD;
ll ans = fac[n];
ll sum1 = 1, sum2 = 1;
for(int i = 1, j; i <= n; i = j) {
for(j = i; j <= n + 1; j++) {
if(p[i].fi != p[j].fi) break;
}
sum1 = sum1 * fac[j - i] % MOD;
}
sort(p + 1, p + n + 1, [&](pii A, pii B) {
return A.se < B.se;
});
for(int i = 1, j; i <= n; i = j) {
for(j = i; j <= n + 1; j++) {
if(p[i].se != p[j].se) break;
}
sum2 = sum2 * fac[j - i] % MOD;
}
ans -= sum1 + sum2;
ans %= MOD; if(ans < 0) ans += MOD;
bool f = 1;
for(int i = 2; i <= n; i++) {
if(p[i].fi < p[i - 1].fi) f = 0;
}
if(f) ans += gao1();
else {
f = 1;
sort(p + 1, p + n + 1);
for(int i = 2; i <= n; i++) {
if(p[i].se < p[i - 1].se) f = 0;
}
if(f) ans += gao2();
}
cout << ans % MOD;
return 0;
}
E. XOR Guessing
题意:
交互题。
先有一个数大小不超过\(2^{14}-1\),给你两次机会,每次询问100个数,对方会告诉你这个数与从100个中随机一个数的异或值。注意所有询问的数都不能重复。
最后输出此答案。
思路:
设答案为\(ans\)。
- 如果二进制一位全都是1,那么此时询问是不是很容易知道\(ans\)?
- 因为不能有重复,并且结合题目,我们就一次询问出一半的情况即可。
Code
#include <bits/stdc++.h>
#define MP make_pair
#define INF 0x3f3f3f3f3f3f3f3f
using namespace std;
typedef long long ll;
const int N = 105;
int a[N], b[N];
int main() {
//ios::sync_with_stdio(false); cin.tie(0);
int now = 0;
for(int i = 7; i <= 13; i++) {
now += (1 << i);
}
for(int i = 1; i <= 100; i++) a[i] = i + now;
now = 0;
for(int i = 0; i <= 6; i++) {
now += (1 << i);
}
int cnt = 0;
for(int s = 0; s < 1 << 7; s++) {
b[++cnt] = (s << 7) + now;
if(cnt == 100) break;
}
int x, y;
cout << "? ";
for(int i = 1; i <= 100; i++) cout << a[i] << ' ';
cout << '\n';
cin >> x;
fflush(stdout);
cout << "? ";
for(int i = 1; i <= 100; i++) cout << b[i] << ' ';
cout << '\n';
cin >> y;
int ans = 0;
for(int i = 7; i < 14; i++) {
if(x >> i & 1) {}
else ans += (1 << i);
}
for(int i = 0; i < 7; i++) {
if(y >> i & 1) {}
else ans += (1 << i);
}
cout << '!' << ' ' << ans;
return 0;
}
F.F. Remainder Problem
题意:
现在数轴上有\(500000\)个位置,先有两个操作:
- \(1\ x\ y:\)表示\(a[x]\)加上\(y\);
- \(2\ x\ y:\)表示对所有满足条件的位置的\(a_i\)求和,这里的满足条件是\(i\% x=y\)。
有\(500000\)次询问,对每次\(2\)操作输出答案。
思路:
- 注意到如果\(x\)比较大,那么我们可以直接暴力的,所以考虑分块。
- 修改的话直接暴力修改,如果\(x>E\),我们就直接暴力询问;否则,直接输出预处理的值。
- 怎么预处理呢?我们首先让\(E=\sqrt{500000}=750\),注意到\(E,y\)都很小,那么我们就开一个数组\(pos[x][y]\)表示模\(x\)余\(y\)所有位置数的和。
- 修改的话同时修改\(pos\)数组即可。
详见代码:
Code
#include <bits/stdc++.h>
#define MP make_pair
#define INF 0x3f3f3f3f3f3f3f3f
#define fi first
#define se second
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
const int N = 500005, E = 750;
int q;
int pos[E][E]; // % x = y
int a[N];
int main() {
ios::sync_with_stdio(false); cin.tie(0);
cin >> q;
while(q--) {
int op, x, y; cin >> op >> x >> y;
if(op == 1) {
a[x] += y;
for(int i = 1; i < E; i++) {
pos[i][x % i] += y;
}
} else {
if(y < 0) y += x;
if(x < E) {
cout << pos[x][y] << '\n';
} else {
int ans = 0;
for(int i = y; i < N; i += x) ans += a[i];
cout << ans << '\n';
}
}
}
return 0;
}
G.Indie Album
题意:
现有两种操作:
- \(1\ c:\)表示以\(c\)开头,重新建立一个字符串;
- \(2\ j\ c:\)表示在第\(j\)个版本后面加上一个字符\(c\),注意每次操作版本都会更新。
同时有多组询问,每组询问如:\("i\ t"\)的格式,询问\(t\)这个字符串在第\(i\)个版本的字符串中出现了多少次。
思路:
类似于阿狸的打字机,考虑离线处理问题。
- 对于1操作,注意到其实并不用重新建立自动机,我们只用关注每个版本的\(end\)位置就好,所以直接拿一个数组记录每个版本的\(end\)位置即可。
- 同时处理出每个询问串所在AC自动机上面的位置。
- 之后就类似于阿狸打字机的套路,将\(fail\)树建出来,跑出\(dfs\)序,用树状数组维护前缀链即可。
- 啥,为啥是前缀链?
- 不就是\(fail\)树求子子串个数的套路么?若\(x\)串在\(y\)串中,那么\(y\)的前缀链肯定存在一个点其\(fail\)是指向\(x\)的,即在\(fail\)树上点\(x\)的子树中。那问题不就是子树求和么。
思路就是这样,但注意一个细节,最后dfs的时候会走错点!!因为我们建fail的时候改变了儿子信息。所以可以事先拿个数组保存一下。
Code
#include <bits/stdc++.h>
#define MP make_pair
using namespace std;
typedef long long ll;
const int N = 1e6 + 5, MAX = 26;
queue <int> q;
int nd[N], in[N], out[N], T;
int res[N], c[N];
vector <pair<int, int> > v[N];
int lowbit(int x){return x & (-x);}
void upd(int x, int v) {
for(; x < N; x += lowbit(x)) c[x] += v;
}
int query(int x) {
int ans = 0;
for(; x; x -= lowbit(x)) ans += c[x];
return ans;
}
int query(int l, int r) {
return query(r) - query(l - 1);
}
struct ACAM{
int sz;
int ch[N][MAX], ch2[N][MAX];
int fail[N];
vector <int> g[N];
int newnode() {
memset(ch[++sz], 0, sizeof(ch[sz]));
fail[sz] = 0;
return sz;
}
void init() {
sz = -1;
newnode();
}
int insert(int u, char *s) {
int len = strlen(s);
for(int i = 0; i < len; i++) {
if(!ch[u][s[i] - 'a']) ch[u][s[i] - 'a'] = newnode();
u = ch[u][s[i] - 'a'];
}
return u;
}
void build() {
for(int i = 0; i <= sz; i++) {
for(int j = 0; j < 26; j++) {
ch2[i][j] = ch[i][j];
}
}
for(int i = 0; i < 26; i++) {
if(ch[0][i]) q.push(ch[0][i]);
}
while(!q.empty()) {
int cur = q.front(); q.pop();
g[fail[cur]].push_back(cur);
for(int i = 0; i < 26; i++) {
if(ch[cur][i]) {
fail[ch[cur][i]] = ch[fail[cur]][i];
q.push(ch[cur][i]);
} else {
ch[cur][i] = ch[fail[cur]][i];
}
}
}
}
void pre(int u) {
in[u] = ++T;
for(auto it : g[u]) pre(it);
out[u] = T;
}
void dfs(int u) {
upd(in[u], 1);
for(auto it : v[u]) {
res[it.second] = query(in[it.first], out[it.first]);
}
for(int i = 0; i < 26; i++) {
if(ch2[u][i]) dfs(ch2[u][i]);
}
upd(in[u], -1);
}
}ac;
int n;
char s[2], str[N];
int main() {
ios::sync_with_stdio(false); cin.tie(0);
cin >> n;
ac.init();
for(int i = 1; i <= n; i++) {
int op; cin >> op;
if(op == 1) {
cin >> s;
nd[i] = ac.insert(0, s);
} else {
int x; cin >> x >> s;
nd[i] = ac.insert(nd[x], s);
}
}
int q; cin >> q;
for(int i = 1; i <= q; i++) {
int x; cin >> x >> str;
v[nd[x]].push_back(MP(ac.insert(0, str), i));
}
ac.build();
ac.pre(0);
ac.dfs(0);
for(int i = 1; i <= q; i++) cout << res[i] << '\n';
return 0;
}
Educational Codeforces Round 71 (Rated for Div. 2)的更多相关文章
- Educational Codeforces Round 71 (Rated for Div. 2)-F. Remainder Problem-技巧分块
Educational Codeforces Round 71 (Rated for Div. 2)-F. Remainder Problem-技巧分块 [Problem Description] ...
- Educational Codeforces Round 71 (Rated for Div. 2)-E. XOR Guessing-交互题
Educational Codeforces Round 71 (Rated for Div. 2)-E. XOR Guessing-交互题 [Problem Description] 总共两次询 ...
- Educational Codeforces Round 71 (Rated for Div. 2)E. XOR Guessing
一道容斥题 如果直接做就是找到所有出现过递减的不同排列,当时硬钢到自闭,然后在凯妹毁人不倦的教导下想到可以容斥做,就是:所有的排列设为a,只考虑第一个非递减设为b,第二个非递减设为c+两个都非递减的情 ...
- Educational Codeforces Round 71 (Rated for Div. 2) E XOR Guessing (二进制分组,交互)
E. XOR Guessing time limit per test1 second memory limit per test256 megabytes inputstandard input o ...
- [暴力] Educational Codeforces Round 71 (Rated for Div. 2) B. Square Filling (1207B)
题目:http://codeforces.com/contest/1207/problem/B B. Square Filling time limit per test 1 second mem ...
- [贪心,dp] Educational Codeforces Round 71 (Rated for Div. 2) C. Gas Pipeline (1207C)
题目:http://codeforces.com/contest/1207/problem/C C. Gas Pipeline time limit per test 2 seconds memo ...
- Educational Codeforces Round 71 (Rated for Div. 2) Solution
A. There Are Two Types Of Burgers 题意: 给一些面包,鸡肉,牛肉,你可以做成鸡肉汉堡或者牛肉汉堡并卖掉 一个鸡肉汉堡需要两个面包和一个鸡肉,牛肉汉堡需要两个面包和一个 ...
- Remainder Problem(分块) Educational Codeforces Round 71 (Rated for Div. 2)
引用:https://blog.csdn.net/qq_41879343/article/details/100565031 下面代码写错了,注意要上面这种.查:2 800 0,下面代码就错了. ...
- XOR Guessing(交互题+思维)Educational Codeforces Round 71 (Rated for Div. 2)
题意:https://codeforc.es/contest/1207/problem/E 答案guessing(0~2^14-1) 有两次机会,内次必须输出不同的100个数,每次系统会随机挑一个你给 ...
随机推荐
- python高阶函数——返回函数(闭包)
首先,来看一个一般意义的求和: >>> def cal_sum(*args): ... sum = 0 ... for i in args: ... sum = sum + i .. ...
- [css flex布局]实例一,本来还想挺简单的,弄了挺久呢,先写一部分
全是代码,直接拷走吧,看是不怎么好看的 参考:http://www.ruanyifeng.com/blog/search.html?cx=016304377626642577906%3Ab_e9ska ...
- HTTP与FILE协议的区别
File协议 file协议(本地文件传输协议)主要是用来访问本地计算机的文件,一般用Windows的资源管理器直接打开进行读取一个HTML文件时,默认会使用file协议 基本格式是: file:/// ...
- SVN 创建发行版/分支版的步骤
最近看了很多 Git 与 SVN 的比较,很多都说 SVN 做分支很慢,不知道是从何说起.有可能大家都不清楚,SVN 做分支的正确步骤,特此介绍一下. SVN 服务器后台使用 Berkeley DB ...
- 使用C#面向对象实现简易计算器(简单工厂模式)
操作流程: 1. 新建Operation类 2. 新建OperationAdd类,并继承Operation类 3. 新建OperationSub类,并继承Operation类 4. 新建Operati ...
- linux bash基础特性
使用history命令,取得命令历史,当bash进程结束后,会把命令历史存放到文件中,下次开机还能看到命令历史. 定制history:通过设置环境变量,来定制history 环境变量$HISTSIZE ...
- 逆向学习周记-C语言空函数
实验环境:WIN7虚拟机 软件:VC6 首先在VC6里面写一个空函数Fun(): F7编译运行一下,没有出错,接着在函数处使用F9下断点,使程序运行到Fun函数时停下. 接着F5开始运行这个程序 程序 ...
- java之集合(Set、List、Map)
java集合类存放于java,uti包中,是一个用于存放对象的容器. 集合只能存放对象,比如存入的是int型数据1,那么它会自动转换成Integer包装类后再存入: 集合存放的是多个对象的引用,对象本 ...
- Codeforces 1238 D. AB-string
思维题 这次cf思维题好多啊 定义了good string 指一个串,其中每一个字符都属于一个长度>=2 的回文串的一部分.叫你求一个串中有几个good substring. 显然ab串 goo ...
- 动态数组原理【Java实现】(六)
前言 接下来我们进入集合学习,看过很多文章一上来就是讲解原理感觉会特别枯燥,任何成熟解决方案的出现都是为了解决问题,若通过实际问题引入然后再来讲解原理想必学起来必定事半功倍,从我写博客的那一天起,我就 ...