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. ios button标记

    在写项目的时候,for循环创建多个button,在需要设置背景图片和,需要标记所选中的button的需求, 在这里提供两种方法: 一: 1:把for循环创建的button全部装到一个新建的数组中,把他 ...

  2. 京东云擎”本周四推出一键免费安装Discuz论坛

    “京东云擎”本周四推出一键免费安装Discuz论坛了,让用户能在1分钟之内建立自己的论坛.这是继上周云擎推出一键安装WordPress之后的又一重大免费贡献! 云擎: http://jae.jd.co ...

  3. 为什么说在js当中所有类的父类是Object类

    代码如下所示: function Parent(add,net,no,teacher) { this.add = add; this.net = net; this.no = no; this.tea ...

  4. 剑指offer练习

    1.题目描述 在一个二维数组中,每一行都按照从左到右递增的顺序排序,每一列都按照从上到下递增的顺序排序.请完成一个函数,输入这样的一个二维数组和一个整数,判断数组中是否含有该整数.  public c ...

  5. 【PHP】算法: 获取满足给定值的最优组合

    PHP 获取给定值的最优组合 方法 -   (蓝洛提供,博客地址: www.zhaorui.info) <?php ini_set('error_reporting','E_ALL^E_NOTI ...

  6. Android Activity与Fragment生命周期 对应关系

  7. 用C或C++为Python编写模块

    1.使用c或c++编写对应的函数例如: //modtest.c int abs(int number){ ){ return -number; } else{ return number; } } 2 ...

  8. 【BZOJ1818】[Cqoi2010]内部白点 扫描线+树状数组

    [BZOJ1818][Cqoi2010]内部白点 Description 无限大正方形网格里有n个黑色的顶点,所有其他顶点都是白色的(网格的顶点即坐标为整数的点,又称整点).每秒钟,所有内部白点同时变 ...

  9. mysql max_allowed_packet参数值改大后,莫名被还原

    mysql数据库用innodb引擎,mysql max_allowed_packet在my.cnf中值加大后,够一段时间,系统会莫名把这个参数的值改小. innodb_buffer_pool_size ...

  10. log4j输出多个自定义日志文件(转)

    如果在实际应用中需要输出独立的日志文件,怎样才能把所需的内容从原有日志中分离,形成单独的日志文件呢? 先看一个常见的log4j.properties文件,它是在控制台和test.log文件中记录日志: ...