A. Dice Rolling

签到.

 #include <bits/stdc++.h>
using namespace std; int t, n; int main()
{
scanf("%d", &t);
while (t--)
{
scanf("%d", &n);
if (n <= ) puts("");
else
{
int res = ;
res += n / ;
printf("%d\n", res + );
}
}
return ;
}

B. Letters Rearranging

签到.

 #include <bits/stdc++.h>
using namespace std; #define N 1010
int t, cnt[];
char s[N]; bool ok()
{
for (int i = , len = strlen(s + ); i < len; ++i) if (s[i] != s[i + ])
return false;
return true;
} int main()
{
scanf("%d", &t);
while (t--)
{
scanf("%s", s + );
if (ok()) puts("-1");
else
{
for (int i = , len = strlen(s + ); i < len; ++i) if(s[i] != s[])
swap(s[i], s[len]);
printf("%s\n", s + );
}
}
return ;
}

C. Mishka and the Last Exam

签到.

 #include <bits/stdc++.h>
using namespace std; #define ll long long
#define N 200010
int n;
ll b[N], a[N]; int main()
{
while (scanf("%d", &n) != EOF)
{
for (int i = ; i <= (n >> ); ++i) scanf("%lld", b + i);
a[] = ; a[n] = b[];
ll base = ;
for (int i = ; i <= (n >> ); ++i)
{
ll gap = b[i] - base - a[n - i + ];
base += max(0ll, gap);
a[i] = base;
a[n - i + ] = b[i] - a[i];
}
for (int i = ; i <= n; ++i) printf("%lld%c", a[i], " \n"[i == n]);
}
return ;
}

D. Beautiful Graph

Solved.

题意:

有$1, 2, 3三种权值,给每个点赋权值$

使得每条边所连的两个点的权值和为奇数,求方案数

思路:

显然,一条边所连的两点的权值分配只有两种

$(2, 1) 或者 (2, 3)$

把$2看作一类,(1, 3)看作一类,就相当于两种颜色染色$

那么判一下是否是二分图就知道有无方案数

再考虑DFS树,对于同属于一个连通块的点构成的DFS树

如果根节点确定了,那么其他结点也就确定要放哪类数字

那么枚举根节点要放的数字类别,对于$(1, 3)这类数字求一下方案数,有两种即可$

 #include <bits/stdc++.h>
using namespace std; #define ll long long
#define N 300010
const ll MOD = ;
int t, n, m;
vector <int> G[N]; ll qmod(ll base, ll n)
{
ll res = ;
while (n)
{
if (n & ) res = (res * base) % MOD;
base = base * base % MOD;
n >>= ;
}
return res;
} int vis[N], deep[N], fa[N], cnt[N];
bool DFS(int u)
{
vis[u] = ;
for (auto v : G[u]) if (v != fa[u])
{
if (vis[v])
{
if ((deep[u] - deep[v]) % == ) return false;
continue;
}
fa[v] = u;
deep[v] = deep[u] + ;
if (DFS(v) == false) return false;
}
return true;
} bool ok()
{
for (int i = ; i <= n; ++i) if (!vis[i])
{
fa[i] = i;
deep[i] = ;
if (DFS(i) == false) return false;
}
return true;
} stack <int> s;
ll DFS(int u, int vi)
{
ll res = ;
vis[u] = ;
s.push(u);
for (auto v : G[u]) if (v != fa[u] && !vis[v])
{
fa[v] = u;
res = (res * (DFS(v, vi ^ )) % MOD);
}
if (vi) return res * % MOD;
else return res;
} ll work()
{
for (int i = ; i <= n; ++i) vis[i] = ;
ll res = ;
for (int i = ; i <= n; ++i) if (!vis[i])
{
while (!s.empty()) s.pop();
fa[i] = i;
ll tmp = DFS(i, );
while (!s.empty())
{
vis[s.top()] = ;
s.pop();
}
tmp = (tmp + DFS(i, )) % MOD;
res = (res * tmp) % MOD;
}
return res;
} int main()
{
scanf("%d", &t);
while (t--)
{
scanf("%d%d", &n, &m);
for (int i = ; i <= n; ++i) G[i].clear(), vis[i] = , cnt[i] = ;
for (int i = , u, v; i <= m; ++i)
{
scanf("%d%d", &u, &v);
G[u].push_back(v);
G[v].push_back(u);
}
if (!ok()) puts("");
else printf("%lld\n", work());
}
return ;
}

E. Intersection of Permutations

Unsolved.

题意:

给出两个排列,两种操作

1° 求$[l_a, r_a]中和[l_b, r_b]中都出现的数的个数$

2° 交换$b排列中两个数的位置$

思路:

CDQ分治:

先$CDQ(l, mid), 再处理当前的(l, r) 在处理(mid + 1, r)$

$但是要注意 处理完(mid + 1, r)后要将换动的位置换回去$

$但是处理了(l, r)之后不要将换动还原,先处理(mid + 1, r),因为这部分的换动是基于(l, r)的$

 #include <bits/stdc++.h>
using namespace std; #define N 200010
int n, m, q, a[N], b[N], posa[N], posb[N];
int qid;
struct qnode
{
int op, pos, l, r, x, y, id;
qnode() {}
qnode(int op, int pos, int x, int y) : op(op), pos(pos), x(x), y(y) {}
bool operator < (const qnode &other) const
{
if (pos != other.pos)
return pos < other.pos;
return op < other.op;
}
}arr[N << ], tarr[N << ];
int ans[N]; namespace BIT
{
int a[N];
void init() { memset(a, , sizeof a); }
void update(int x, int val)
{
for (; x < N; x += x & -x)
a[x] += val;
}
int query(int x)
{
int res = ;
for (; x > ; x -= x & -x)
res += a[x];
return res;
}
int query(int l, int r)
{
if (r < l) return ;
return query(r) - query(l - );
}
}; void CDQ(int l, int r)
{
if (r <= l) return;
int mid = (l + r) >> ;
CDQ(l, mid);
int w = ;
for (int i = l; i <= mid; ++i)
{
if (arr[i].op != )
{
if (arr[i].op == )
tarr[++w] = arr[i];
else
{
int x = arr[i].x, y = arr[i].y;
int A = posa[b[x]];
int B = posa[b[y]];
tarr[++w] = qnode(, A, x, -);
tarr[++w] = qnode(, A, y, );
tarr[++w] = qnode(, B, y, -);
tarr[++w] = qnode(, B, x, );
swap(b[x], b[y]);
}
}
}
for (int i = mid + ; i <= r; ++i)
{
if (arr[i].op == )
tarr[++w] = arr[i];
}
sort(tarr + , tarr + + w);
for (int i = ; i <= w; ++i)
{
if (tarr[i].op == )
BIT::update(tarr[i].x, tarr[i].y);
else
ans[tarr[i].id] += BIT::query(tarr[i].l, tarr[i].r) * tarr[i].y;
}
for (int i = ; i <= w; ++i) if (tarr[i].op == )
BIT::update(tarr[i].x, -tarr[i].y);
//printf("%d %d %d\n", l, mid, r);
//for (int i = 1; i <= qid; ++i) printf("%d%c", ans[i], " \n"[i == qid]);
CDQ(mid + , r);
for (int i = mid; i >= l; --i) if (arr[i].op == ) swap(b[arr[i].x], b[arr[i].y]);
} int main()
{
while (scanf("%d%d", &n, &m) != EOF)
{
memset(ans, , sizeof ans); BIT::init();
for (int i = ; i <= n; ++i) scanf("%d", a + i);
for (int i = ; i <= n; ++i) scanf("%d", b + i);
for (int i = ; i <= n; ++i) posa[a[i]] = i;
for (int i = ; i <= n; ++i) posb[b[i]] = i;
int op, la, ra, lb, rb, x, y; q = ; qid = ;
for (int i = ; i <= n; ++i)
arr[++q] = qnode(, i, posb[a[i]], );
for (int i = ; i <= m; ++i)
{
scanf("%d", &op);
if (op == )
{
++qid;
scanf("%d%d%d%d", &la, &ra, &lb, &rb);
arr[++q].op = ;
arr[q].pos = la - ;
arr[q].l = lb;
arr[q].r = rb;
arr[q].id = qid;
arr[q].y = -;
arr[++q].op = ;
arr[q].pos = ra;
arr[q].l = lb;
arr[q].r = rb;
arr[q].id = qid;
arr[q].y = ;
}
else
{
scanf("%d%d", &x, &y);
arr[++q].op = ;
arr[q].x = x;
arr[q].y = y;
}
}
CDQ(, q);
for (int i = ; i <= qid; ++i) printf("%d\n", ans[i]);
}
return ;
}

分块极限卡过:

对$b[]分块,整块二分查找,角块暴力$

查询复杂度$O(\frac{n}{S} \cdot log(S))$

修改复杂度$O(S \cdot log(S))$

让这两个复杂度尽量相等即可

时间复杂度$O(n\sqrt{n}log(\sqrt{n}))$

 #include <bits/stdc++.h>
using namespace std; #define N 200010
#define unit 400
#define S 1010
int n, m, a[N], b[N]; int pos[N], posl[S], posr[S];
vector <int> v[S]; bool in(int x, int a, int b)
{
if (x >= a && x <= b) return true;
return false;
} int query(int l, int r, int x, int y)
{
int res = ;
if (pos[l] == pos[r])
{
for (int i = l; i <= r; ++i) if (in(a[b[i]], x, y))
++res;
}
else
{
for (int i = l; i <= posr[pos[l]]; ++i) if (in(a[b[i]], x, y))
++res;
for (int i = posl[pos[r]]; i <= r; ++i) if (in(a[b[i]], x, y))
++res;
for (int i = pos[l] + ; i <= pos[r] - ; ++i)
res += upper_bound(v[i].begin(), v[i].end(), y) - lower_bound(v[i].begin(), v[i].end(), x);
}
return res;
} void update(int x)
{
v[x].clear();
for (int i = posl[x]; i <= posr[x]; ++i) v[x].push_back(a[b[i]]);
sort(v[x].begin(), v[x].end());
} int main()
{
while (scanf("%d%d", &n, &m) != EOF)
{
for (int i = ; i <= n; ++i) pos[i] = (i - ) / unit + ;
for (int i = ; i <= n; ++i)
{
posr[pos[i]] = i;
if (i == || pos[i] != pos[i - ])
posl[pos[i]] = i;
}
for (int i = ; i <= pos[n]; ++i) v[i].clear();
for (int i = , x; i <= n; ++i)
{
scanf("%d", &x);
a[x] = i;
}
for (int i = ; i <= n; ++i) scanf("%d", b + i);
for (int i = ; i <= n; ++i)
v[pos[i]].push_back(a[b[i]]);
for (int i = ; i <= pos[n]; ++i) sort(v[i].begin(), v[i].end());
int op, l[], r[], x, y;
for (int i = ; i <= m; ++i)
{
scanf("%d", &op);
if (op == )
{
for (int i = ; i < ; ++i) scanf("%d%d", l + i, r + i);
printf("%d\n", query(l[], r[], l[], r[]));
}
else
{
scanf("%d%d", &x, &y);
swap(b[x], b[y]);
update(pos[x]);
if (pos[x] != pos[y]) update(pos[y]);
}
}
}
return ;
}

分块:

对$a[], b[]分别分块$

$维护一个sum[i][j]表示b的第i块对a的前j块的贡献$

$整块的贡献一起处理,角块暴力$

$修改的时候只有两个整块会有变化,暴力重构$

时间复杂度$O(n\sqrt{n})$

 #include <bits/stdc++.h>
using namespace std; #define N 200010
#define unit 250
#define M 1010
int n, m;
int a[N], b[N], A[N], B[N];
int pos[N], posl[M], posr[M];
int sum[M][M], f[M][M]; int main()
{
while (scanf("%d%d", &n, &m) != EOF)
{
for (int i = ; i <= n; ++i) pos[i] = (i - ) / unit + ;
for (int i = ; i <= n; ++i)
{
if (i == || pos[i] != pos[i - ]) posl[pos[i]] = i;
posr[pos[i]] = i;
}
for (int i = ; i <= n; ++i) scanf("%d", a + i), A[a[i]] = i;
for (int i = ; i <= n; ++i) scanf("%d", b + i), B[b[i]] = i;
for (int i = ; i <= n; ++i)
++f[pos[i]][pos[A[b[i]]]];
for (int i = ; i <= pos[n]; ++i)
for (int j = ; j <= pos[n]; ++j)
sum[i][j] += sum[i][j - ] + f[i][j];
int op, la, ra, lb, rb, x, y;
while (m--)
{
scanf("%d", &op);
if (op == )
{
int res = ;
scanf("%d%d%d%d", &la, &ra, &lb, &rb);
if (pos[la] == pos[ra])
{
for (int i = la; i <= ra; ++i)
res += (B[a[i]] >= lb && B[a[i]] <= rb);
}
else if (pos[lb] == pos[rb])
{
for (int i = lb; i <= rb; ++i)
res += (A[b[i]] >= la && A[b[i]] <= ra);
}
else
{
for (int i = pos[lb] + ; i < pos[rb]; ++i)
res += sum[i][pos[ra] - ] - sum[i][pos[la]];
for (int i = la; i <= posr[pos[la]]; ++i)
res += (B[a[i]] >= lb && B[a[i]] <= rb);
for (int i = posl[pos[ra]]; i <= ra; ++i)
res += (B[a[i]] >= lb && B[a[i]] <= rb);
for (int i = lb; i <= posr[pos[lb]]; ++i)
res += (A[b[i]] >= posl[pos[la] + ] && A[b[i]] <= posr[pos[ra] - ]);
for (int i = posl[pos[rb]]; i <= rb; ++i)
res += (A[b[i]] >= posl[pos[la] + ] && A[b[i]] <= posr[pos[ra] - ]);
}
printf("%d\n", res);
}
else
{
int id;
scanf("%d%d", &x, &y);
id = A[b[x]];
--f[pos[x]][pos[id]];
id = A[b[y]];
--f[pos[y]][pos[id]];
swap(B[b[x]], B[b[y]]);
swap(b[x], b[y]);
id = A[b[x]];
++f[pos[x]][pos[id]];
id = A[b[y]];
++f[pos[y]][pos[id]];
for (int i = ; i <= pos[n]; ++i) sum[pos[x]][i] = sum[pos[x]][i - ] + f[pos[x]][i];
for (int i = ; i <= pos[n]; ++i) sum[pos[y]][i] = sum[pos[y]][i - ] + f[pos[y]][i];
}
}
}
return ;
}

F. Vasya and Array

Upsolved.

题意:

给出一个序列,有些位置有数,有些位置没有,可以自己填$[1, k]中的数$

求没有一段长度为$len的连续的序列是同一个数的填数方案$

思路:

$dp[i][j]表示第i个位置放第j个数的方案,sum[i] = \sum_{j = 1}^{k}dp[i][j]$

再考虑转移

$如果a[i] == -1,那么枚举[1, k]每个数,转移的时候就是dp[i][j] = sum[i - 1]$

但是要减去不合法的状态

不合法的状态就是$sum[i - len] - dp[i - len][j]$

为什么要减去$dp[i - len][j],因为这是长度为len + 1 的, 在之前减去过$

对于$a[i] = 特定的数的转移也如此$

 #include <bits/stdc++.h>
using namespace std; #define ll long long
#define N 100010
const ll MOD = ;
int n, k, l, a[N];
ll dp[N][], sum[N], len[]; int main()
{
while (scanf("%d%d%d", &n, &k, &l) != EOF)
{
for (int i = ; i <= n; ++i) scanf("%d", a + i);
memset(dp, , sizeof dp);
memset(sum, , sizeof sum);
memset(len, , sizeof len);
sum[] = ;
for (int i = ; i <= n; ++i)
{
for (int j = ; j <= k; ++j) len[j] = (a[i] == - || a[i] == j) ? len[j] + : ;
if (a[i] == -)
{
for (int j = ; j <= k; ++j)
{
dp[i][j] = sum[i - ];
if (len[j] >= l)
dp[i][j] = (dp[i][j] - (sum[i - l] - dp[i - l][j] + MOD) % MOD + MOD) % MOD;
}
}
else
{
dp[i][a[i]] = sum[i - ];
if (len[a[i]] >= l)
dp[i][a[i]] = (dp[i][a[i]] - (sum[i - l] - dp[i - l][a[i]] + MOD) % MOD + MOD) % MOD;
}
for (int j = ; j <= k; ++j) sum[i] = (sum[i] + dp[i][j]) % MOD;
}
printf("%lld\n", sum[n]);
}
return ;
}

G. Multidimensional Queries

Upsolved.

题意:

在一个k维平面上求区间两点最远曼哈顿距离

思路:

曼哈顿距离可以通过枚举符号的正负状态来取最大值

注意到$k并不大,那么线段树维护在一种符号状态下的最大和最小值即可$

会有一些不合法的状态,但是这些不合法的状态一定会有另外一个合法的状态并且使得答案比不合法状态更优

所以不合法状态是不用管的

 #include <bits/stdc++.h>
using namespace std; #define N 200010
#define INF 0x3f3f3f3f
int n, k, q, a[N][]; struct SEG
{
struct node
{
int Max, Min;
node () {}
node (int Max, int Min) : Max(Max), Min(Min) {}
void init() { Max = -INF, Min = INF; }
node operator + (const node &other) const { return node (max(Max, other.Max), min(Min, other.Min)); }
}a[N << ], res;
void build(int id, int l, int r)
{
a[id].init();
if (l == r) return;
int mid = (l + r) >> ;
build(id << , l, mid);
build(id << | , mid + , r);
}
void update(int id, int l, int r, int pos, int val)
{
if (l == r)
{
a[id] = node(val, val);
return;
}
int mid = (l + r) >> ;
if (pos <= mid) update(id << , l, mid, pos, val);
else update(id << | , mid + , r, pos, val);
a[id] = a[id << ] + a[id << | ];
}
void query(int id, int l, int r, int ql, int qr)
{
if (l >= ql && r <= qr)
{
res = res + a[id];
return;
}
int mid = (l + r) >> ;
if (ql <= mid) query(id << , l, mid, ql, qr);
if (qr > mid) query(id << | , mid + , r, ql, qr);
}
}seg[ << ]; int main()
{
while (scanf("%d%d", &n, &k) != EOF)
{
for (int i = ; i <= n; ++i) for (int j = ; j < k; ++j) scanf("%d", a[i] + j);
for (int i = ; i < ( << k); ++i)
{
seg[i].build(, , n);
for (int j = ; j <= n; ++j)
{
int tmp = ;
for (int o = ; o < k; ++o)
tmp += a[j][o] * ((((i >> o) & ) == ) ? - : );
seg[i].update(, , n, j, tmp);
}
}
scanf("%d", &q);
for (int i = , op, x, l, r; i <= q; ++i)
{
scanf("%d", &op);
if (op == )
{
scanf("%d", &x);
for (int j = ; j < k; ++j) scanf("%d", a[x] + j);
for (int j = ; j < ( << k); ++j)
{
int tmp = ;
for (int o = ; o < k; ++o)
tmp += a[x][o] * (((j >> o) & ) == ? - : );
seg[j].update(, , n, x, tmp);
}
}
else
{
scanf("%d%d", &l, &r);
int res = -INF;
for (int j = ; j < ( << k); ++j)
{
seg[j].res.init();
seg[j].query(, , n, l, r);
res = max(res, seg[j].res.Max - seg[j].res.Min);
}
printf("%d\n", res);
}
}
}
return ;
}

Educational Codeforces Round 56 Solution的更多相关文章

  1. Multidimensional Queries(二进制枚举+线段树+Educational Codeforces Round 56 (Rated for Div. 2))

    题目链接: https://codeforces.com/contest/1093/problem/G 题目: 题意: 在k维空间中有n个点,每次给你两种操作,一种是将某一个点的坐标改为另一个坐标,一 ...

  2. Educational Codeforces Round 56 (Rated for Div. 2) D. Beautiful Graph 【规律 && DFS】

    传送门:http://codeforces.com/contest/1093/problem/D D. Beautiful Graph time limit per test 2 seconds me ...

  3. Educational Codeforces Round 56 (Rated for Div. 2) ABCD

    题目链接:https://codeforces.com/contest/1093 A. Dice Rolling 题意: 有一个号数为2-7的骰子,现在有一个人他想扔到几就能扔到几,现在问需要扔多少次 ...

  4. Educational Codeforces Round 56 (Rated for Div. 2) D

    给你一个无向图 以及点的个数和边  每个节点只能用1 2 3 三个数字 求相邻 两个节点和为奇数   能否构成以及有多少种构成方法 #include<bits/stdc++.h> usin ...

  5. Educational Codeforces Round 56 (Rated for Div. 2)

    涨rating啦.. 不过话说为什么有这么多数据结构题啊,难道是中国人出的? A - Dice Rolling 傻逼题,可以用一个三加一堆二或者用一堆二,那就直接.. #include<cstd ...

  6. Educational Codeforces Round 56 Div. 2 翻车记

    A:签到. B:仅当只有一种字符时无法构成非回文串. #include<iostream> #include<cstdio> #include<cmath> #in ...

  7. Educational Codeforces Round 56 (Rated for Div. 2) F - Vasya and Array dp好题

    F - Vasya and Array dp[ i ][ j ] 表示用了前 i 个数字并且最后一个数字是 j 的方案数. dp[ i ][ j ] = sumdp [i - 1 ][ j ], 这样 ...

  8. Educational Codeforces Round 57 Solution

    A. Find Divisible 签到. #include <bits/stdc++.h> using namespace std; int t, l, r; int main() { ...

  9. Educational Codeforces Round 58 Solution

    A. Minimum Integer 签到. #include <bits/stdc++.h> using namespace std; #define ll long long ll l ...

随机推荐

  1. python2.0_s12_day12_html介绍

    html 就像一个裸体的人css 就像是人穿的衣服js 就像是人做的动作一.网页文件HTML的构成 1.对应规则的选择,就如同我们写python时#!/usr/bin/env python3.5 这么 ...

  2. CentOS 6.3下部署LVS(NAT模式)+keepalived实现高性能高可用负载均衡

    一.简介 VS/NAT原理图: 二.系统环境 实验拓扑: 系统平台:CentOS 6.3 Kernel:2.6.32-279.el6.i686 LVS版本:ipvsadm-1.26 keepalive ...

  3. PHP虚拟主机的配置

    今天配置了一下虚拟目录,以下是我的配置方法. 1  编辑httpd.conf,查找Include conf/extra/httpd-vhosts.conf,把前面注释符号“#”删掉. 2  编辑htt ...

  4. iOS 数据类型转换

    1.NSString转化为UNICODE String:(NSString*)fname = @“Test”; char fnameStr[10]; memcpy(fnameStr, [fname c ...

  5. CentOS7安装Openvswitch 2.3.1 LTS

    CentOS7安装Openvswitch 2.3.0 LTS,centos7openvswitch 一.环境: 宿主机:windows 8.1 update 3 虚拟机:vmware 11 虚拟机操作 ...

  6. CSS-项目中遇到IE兼容问题,处理随笔

    总是忘记给ie做特殊样式处理,以前打游击,不做也就算了,以后可不行,得对自己的“孩子”负责.. 一.先说IE老大的兼容 知道了一些常用的css属性兼容方法确实可以解决问题, 但我不知道我自己的ieTe ...

  7. jstl标签怎么实现分页中下一页

    <script type="text/javascript">           //分页按钮处理        function goPageAction(page ...

  8. log4j和commons- logging(好文整理转载)

    一 :为什么同时使用commons-logging和Log4j?为什么不仅使用其中之一? Commons-loggin的目的是为 “所有的Java日志实现”提供一个统一的接口,它自身的日志功能平常弱( ...

  9. WEB安全番外第二篇--明日之星介绍HTML5安全问题介绍

    一.CORS领域问题: 1.CORS的介绍请参考:跨域资源共享简介 2.HTML5中的XHR2级调用可以打开一个socket连接,发送HTTP请求,有趣的是,上传文件这里恰恰是multi-part/f ...

  10. c# Use NAudio Library to Convert MP3 audio into WAV audio(将Mp3格式转换成Wav格式)

    Have you been in need of converting mp3 audios to wav audios?  If so, the skill in this article prov ...