この相対的に言って、少し友情は、それについては数日前に構成して、その後、送信するために忘れていました...
ソリューションは、次のような問題が含まれる:(\ \ \ \ B \ \ \ F. \ \ \ G \ \ \ H \ \ \ J \)
\(D \)までの彼のチームメイトを疑問視し、私は数式の問題を考えるためにわざわざので、会場やその他の問題の解決策はありません。
コンテスト住所: https://ac.nowcoder.com/acm/contest/883#question
[A]グラフゲームランダムブロック+
所与の(\ N-)\点と\(m個\)を定義エッジ\を(S(x)が\)であり、(X \)\隣接点のセットのすべての点について。以下のために\(Q \)の操作、二つのタイプに分け:
- フリップ\([L、R] \ ) 間隔内の状態がある- >エッジを削除し、何も存在しない- >ボーダー
- 掲載(\)S(U)を\に等しいです\(S(V)\)
前記\(N- \のLeq 1E。5 ^ \ \ m個の\のLeq 2E 5 ^ \ \ Q \のLeq 2E 5 ^ \) 。
連続した全体の同じセットを満たすために必要として、各チェックポイントならば、この複雑さは爆破されました。したがって割り当てると考え各点乱数を異なる乱数を用いたが、同じセットかどうかを決定する又は矛盾する場合には発生しない(おそらく)を示すことができます。
巨大な範囲のための使用が必要ですブロック更新のためのブロックで複雑さを軽減するために操作する直接更新することができ、更新のためのブロック間、そして使用する必要が\(怠惰\は)で標識した\(怠惰== 1 \)考慮すべき現在のブロックの必要性を表しています。\(SUM \)の各点の重み値は、各メモリアレイに更新する、\(S \)のアレイを更新することができる各シングルポイント値に対して記憶されます。
理解するためのコードを勧告。
#include <map>
#include <set>
#include <list>
#include <cmath>
#include <ctime>
#include <deque>
#include <stack>
#include <queue>
#include <bitset>
#include <cctype>
#include <cstdio>
#include <vector>
#include <string>
#include <cstdlib>
#include <cstring>
#include <fstream>
#include <iomanip>
#include <numeric>
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const double PI = acos(-1.0);
const double eps = 1e-6;
const int inf = 0x3f3f3f3f;
const int mod = 1e9 + 7;
const int maxn = 2e5+5;
const int sqrtn = 5e2+5;
int n, m;
int num;
int block;
int u[maxn];
int v[maxn];
int val[maxn]; // 随机权值(大概可以保证异或值不发生冲突【重复】)
int belong[maxn];
int l[sqrtn];
int r[sqrtn];
int lazy[sqrtn]; // 整块翻转标记
ll s[maxn]; // 每个点的异或值
ll sum[sqrtn][maxn];// 每块里每个点待更新的权值
void build() { // 分块建立
block = sqrt(m);
num = m / block;
if(m % block != 0) {
num ++;
}
for(int i = 1; i <= num; i++) {
l[i] = (i-1)*block + 1;
r[i] = i*block;
lazy[i] = 1; // 初始赋值 1 代表当前块可以使用
for(int j = 1; j <= n; j++) {
sum[i][j] = 0;
}
}
r[num] = m;
for(int i = 1; i <= m; i++) {
belong[i] = (i-1)/block+1;
}
for(int i = 1; i <= n; i++) {
s[i] = 0;
}
}
void update(int l, int r) { // 分块更新
if(belong[l] == belong[r]) {
for(int i = l; i <= r; i++) {
s[u[i]] ^= val[v[i]];
s[v[i]] ^= val[u[i]];
}
return ;
}
for(int i = l; belong[i] == belong[l]; i++) {
s[u[i]] ^= val[v[i]];
s[v[i]] ^= val[u[i]];
}
for(int i = r; belong[i] == belong[r]; i--) {
s[u[i]] ^= val[v[i]];
s[v[i]] ^= val[u[i]];
}
for(int i = belong[l]+1; i < belong[r]; i++) {
lazy[i] ^= 1; // 翻转
}
}
int main() {
srand(time(NULL));
for(int i = 0; i < maxn; i++) {
// 每个点赋予随机权值,加点删点都是异或操作
val[i] = rand() + 1;
}
int t;
scanf("%d", &t);
while(t--) {
scanf("%d%d", &n, &m);
build(); // 按 m 分块
for(int i = 1; i <= m; i++) {
scanf("%d%d", &u[i], &v[i]);
sum[belong[i]][u[i]] ^= val[v[i]];
sum[belong[i]][v[i]] ^= val[u[i]];
}
int q;
scanf("%d", &q);
for(int i = 1; i <= q; i++) {
int f, x, y;
scanf("%d%d%d", &f, &x, &y);
if(f == 1) {
update(x, y);
}
else {
ll ans1 = s[x]; // 单点的情况
ll ans2 = s[y];
for(int i = 1; i <= num; i++) { // 整块的情况
if(lazy[i]) {
ans1 ^= sum[i][x];
ans2 ^= sum[i][y];
}
}
if(ans1 == ans2) {
printf("1");
}
else {
printf("0");
}
}
}
printf("\n");
}
return 0;
}
[B]クレイジーバイナリ列貪欲
所与\(01 \)文字列を選択したとする最長のサブ配列、のいずれか\(0 \)と\(1 \)同じ数。
それは明らかであるシーケンス区間のための\(分(sum_1、sum_0)\) 。
サブストリングのプレフィックスを維持し、その後、最初の出現と同じ値の場所を見つける必要があります。
#include <map>
#include <set>
#include <list>
#include <cmath>
#include <ctime>
#include <deque>
#include <stack>
#include <queue>
#include <bitset>
#include <cctype>
#include <cstdio>
#include <vector>
#include <string>
#include <cstdlib>
#include <cstring>
#include <fstream>
#include <iomanip>
#include <numeric>
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const double PI = acos(-1.0);
const double eps = 1e-6;
const int inf = 0x3f3f3f3f;
const int mod = 1e9 + 7;
const int maxn = 1e5+5;
char s[maxn];
map<int, int> mp;
int main() {
int n;
while(~scanf("%d", &n)) {
scanf("%s", s+1);
int a = 0, b;
mp.clear();
int x = 0, y = 0;
int cnt = 0;
for(int i = 1; i <= n; i++) {
if(s[i] == '0') {
x ++;
cnt --;
if(cnt == 0) {
a = max(a, i);
continue;
}
if(mp[cnt] == 0) {
mp[cnt] = i;
continue;
}
a = max(a, i-mp[cnt]);
}
else {
y ++;
cnt ++;
if(cnt == 0) {
a = max(a, i);
continue;
}
if(mp[cnt] == 0) {
mp[cnt] = i;
continue;
}
a = max(a, i-mp[cnt]);
}
}
b = min(x, y) * 2;
printf("%d %d\n", a, b);
}
return 0;
}
[F]植林キューモノトーン
所与\(N * N \)の各点の重み行列と値\({}のA_ ijを\) 、最大の矩形を見つけるために、そのような最大矩形以下での内部重みの最小値との差すなわち\(m個\) 。
現在の最大値、最小メンテナンス別のを維持するために、2つのキューを定義する単調な必要性、そして...それは、のようなコードを見て、あまりにも複雑であると言います。追加で\(両端キュー\)私はTLEた場合は直接、手書きそう。
#include <map>
#include <set>
#include <list>
#include <cmath>
#include <ctime>
#include <deque>
#include <stack>
#include <queue>
#include <bitset>
#include <cctype>
#include <cstdio>
#include <vector>
#include <string>
#include <cstdlib>
#include <cstring>
#include <fstream>
#include <iomanip>
#include <numeric>
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const double PI = acos(-1.0);
const double eps = 1e-6;
const int inf = 0x3f3f3f3f;
const int mod = 1e9 + 7;
const int maxn = 5e2+5;
int cmax[maxn], cmin[maxn]; // 列最大最小值
int qmax[maxn*2], qmin[maxn*2]; // 单调队列(双端)
int a[maxn][maxn];
int l1, r1, l2, r2;
int ans, n, m;
int solve() {
l1 = l2 = 0;
r1 = r2 = 0;
int x = 1;
int temp = 0;
memset(qmin, 0, sizeof(qmin));
memset(qmax, 0, sizeof(qmax));
for(int i = 1; i <= n; i++) {
while(l1 < r1 && cmax[qmax[r1-1]] < cmax[i]) {
r1--;
}
qmax[r1++] = i;
while(l2 < r2 && cmin[qmin[r2-1]] > cmin[i]) {
r2--;
}
qmin[r2++] = i;
while(l1 < r1 && l2 < r2 && cmax[qmax[l1]] - cmin[qmin[l2]] > m && x <= i) {
x = min(qmax[l1], qmin[l2])+1;
if(qmax[l1] < qmin[l2]) {
l1++;
}
else if(qmax[l1] > qmin[l2]) {
l2++;
}
else {
l1++;
l2++;
}
}
temp = max(temp, i-x+1);
}
return temp;
}
int main() {
int t;
scanf("%d", &t);
while(t--) {
ans = 0;
scanf("%d%d", &n, &m);
for(int i = 1; i <= n; i ++) {
for(int j = 1; j <= n; j++) {
scanf("%d", &a[i][j]);
}
}
for(int i = 1; i <= n; i++) {
for(int k = 1; k <= n; k++) {
cmax[k] = 0;
cmin[k] = inf;
}
for(int j = i; j <= n; j++) {
for(int k = 1; k <= n; k++) {
cmax[k] = max(cmax[k], a[j][k]);
cmin[k] = min(cmin[k], a[j][k]);
}
ans = max(ans, solve()*(j-i+1));
}
}
printf("%d\n", ans);
}
return 0;
}
ストーンズRMQ +二分を削除する【G】
与えられた\(N- \)最後の光が、それは勝つことができる取ることができれば、スタック石、各非空の杭は、それぞれの石の除去を選択することができます。Q.は、多くのセクションが存在するどのように\([L、R] \) 、勝利スペースの定義を満たします。間隔内の石の合計数が奇数の場合、さらに、最初の最小数は、石の山を取り除きます。
勝利のゲーム条件:石のセクションの合計数と\(SUM \) > =二回の間隔の最大値\(最大\) 。
だから、最初の使用\(RMQ \)あなたが最高の価値を見つけることができる範囲の管轄境界は、その区間の寄与は区間内の石の山で最大の数でカウントされ、石の処理の前に\を([L、R] \) 、その後、半分の反対側を探して、側面を列挙。
#include <map>
#include <set>
#include <list>
#include <cmath>
#include <ctime>
#include <deque>
#include <stack>
#include <queue>
#include <bitset>
#include <cctype>
#include <cstdio>
#include <vector>
#include <string>
#include <cstdlib>
#include <cstring>
#include <fstream>
#include <iomanip>
#include <numeric>
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const double PI = acos(-1.0);
const double eps = 1e-6;
const int inf = 0x3f3f3f3f;
const int mod = 1e9 + 7;
const int maxn = 300000+5;
int dp_max[maxn][25]; // 维护区间最大值
int pos[maxn][25]; // 维护区间最大值的位置
int a[maxn];
int n;
ll sum_f[maxn]; // 前缀和
ll sum_b[maxn]; // 后缀和
void RMQ() {
for(int i = 1; i <= n; i++) {
dp_max[i][0] = a[i];
pos[i][0] = i;
}
for(int j = 1; (1<<j) <= n; j++) {
for(int i = 1; i+(1<<j)-1 <= n; i++) {
if(dp_max[i][j-1] >= dp_max[i+(1<<(j-1))][j-1]) {
dp_max[i][j] = dp_max[i][j-1];
pos[i][j] = pos[i][j-1];
}
else {
dp_max[i][j] = dp_max[i+(1<<(j-1))][j-1];
pos[i][j] = pos[i+(1<<(j-1))][j-1];
}
}
}
}
int query_pos(int l, int r) { // 查询区间最值所在位置
int k = log2(r-l+1);
if(dp_max[l][k] >= dp_max[r-(1<<k)+1][k]) {
return pos[l][k];
}
return pos[r-(1<<k)+1][k];
}
ll solve(int l, int r) {
if(l >= r) {
return 0;
}
int p = query_pos(l, r); // 区间最值位置
// printf("l == %d r == %d p == %d\n", l, r, p);
ll ans = 0;
if(p-l < r-p) { // 更靠近左端点
for(int i = l; i <= p; i++) {
ans += (r - (lower_bound(sum_f+p, sum_f+r+1, sum_f[i-1]+2*a[p])-(sum_f+1)));
// 区间和必须 >= 二倍区间最大值【条件x】
// 对答案的贡献 == (右端点位置 - 满足条件的最左端【满足条件x】)
}
}
else {
for(int i = p; i <= r; i++) {
ans += ((n-l+1) - (lower_bound(sum_b+(n-p+1), sum_b+(n-l+1)+1, sum_b[n-i]+2*a[p])-(sum_b+1)));
// 后缀是反着存的,所以处理时也是反着
}
}
return ans + solve(l, p-1) + solve(p+1, r);
}
int main() {
int t;
scanf("%d", &t);
while(t--) {
scanf("%d", &n);
sum_f[0] = sum_b[0] = 0;
for(int i = 1; i <= n; i++) {
scanf("%d", &a[i]);
sum_f[i] = sum_f[i-1] + a[i];
}
for(int i = 1; i <= n; i++) {
sum_b[i] = sum_b[i-1] + a[n-i+1];
}
RMQ();
printf("%lld\n", solve(1, n));
}
return 0;
}
[H]マジックラインの数学
二次元平面の所与\(N \) (偶数)点、これらは同様に2つの直線上の任意の二つの座標(整数)の出力に分割直線n個の点を描画する必要があります。
ゲームはまだあまり考えるには少し時間で、ACをソート問題を解決するには、2つのキーワードを指示することができるようになりますが、私の解決策は、最初はかなり遠くから[]第三象限のポイントを見つけることです、そしてこの時点では"です\( Pは\)「ソートする極角を、およびソートが取られている」ポイント中間点「と点\(P \)には、横軸を-1接続のもう一方の端を取るためにポイントを(および保証するものではありません」中間点「が交差します)。
#include <map>
#include <set>
#include <list>
#include <cmath>
#include <ctime>
#include <deque>
#include <stack>
#include <queue>
#include <bitset>
#include <cctype>
#include <cstdio>
#include <vector>
#include <string>
#include <cstdlib>
#include <cstring>
#include <fstream>
#include <iomanip>
#include <numeric>
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const double PI = acos(-1.0);
const double eps = 1e-6;
const int inf = 0x3f3f3f3f;
const int mod = 1e9 + 7;
const int maxn = 1e5+5;
struct node {
ll x, y;
}p[maxn];
ll jud(node p1, node p2, node p0) {
ll ans = (p1.x-p0.x)*(p2.y-p0.y) - (p2.x-p0.x)*(p1.y-p0.y);
return ans;
}
bool cmp(node a, node b) {
ll c = jud(node{-100000000, -10000}, b, a);
return c < 0;
}
int main() {
int t;
scanf("%d", &t);
while(t--) {
int n;
scanf("%d", &n);
for(int i = 1; i <= n; i++) {
scanf("%lld%lld", &p[i].x, &p[i].y);
}
sort(p+1, p+1+n, cmp);
ll x = p[n/2].x;
ll y = p[n/2].y;
ll xx = 2*x + 100000000;
ll yy = 2*y + 10000;
printf("-100000000 -10000 %lld %lld\n", xx-1, yy);
}
return 0;
}
LRU管理シミュレーション[J]
アナログLRUアルゴリズム:
- 追加\(ブロック\)を、それがすでに存在する場合、キャッシュに、それが最後に移動されます
- クエリ\(ブロック\)(1)データ存在する場合、キャッシュ内にその前身(-1)の出力であるか、またはそれ自体(0)またはその後継
そして、彼のチームメイトは、迷惑に大きなシミュレーションを一緒に記述する必要があります。[直接文字列TLEと(どのようなものを持っていない)ので、我々はデジタルに変換する必要があります]。
牛顧客評価チー先祖TLE、限り、あなたは十分な時間を試してみてきたように、ACのことができるようになります。
#include <map>
#include <set>
#include <list>
#include <cmath>
#include <ctime>
#include <deque>
#include <stack>
#include <queue>
#include <bitset>
#include <cctype>
#include <cstdio>
#include <vector>
#include <string>
#include <cstdlib>
#include <cstring>
#include <fstream>
#include <iomanip>
#include <numeric>
#include <iostream>
#include <algorithm>
#include <unordered_map>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const double PI = acos(-1.0);
const double eps = 1e-6;
const int inf = 0x3f3f3f3f;
const int mod = 1e9 + 7;
struct node {
int pos;
ll name;
int val;
bool operator < (const node &x) const {
return pos < x.pos;
}
};
set<node> SS;
unordered_map<ll, int> vis;
int main() {
int t;
scanf("%d", &t);
while(t--) {
SS.clear();
vis.clear();
int q, m;
scanf("%d%d", &q, &m);
int tot = 0;
while(q--) {
int op, v;
char x[15];
scanf("%d%s%d", &op, x, &v);
int l = strlen(x);
ll s = 0;
for(int i = 0; i < l; i++) {
s = s*11+x[i]-'0';
}
if(op == 0) {
if(vis[s] == 0) {
if(SS.size() == m) {
vis[SS.begin()->name] = 0;
SS.erase(SS.begin());
}
SS.insert(node{++tot, s, v});
vis[s] = tot;
printf("%d\n", v);
}
else {
auto it = SS.lower_bound(node{vis[s], 0, 0});
node temp = *it;
SS.erase(it);
temp.pos = ++tot;
SS.insert(temp);
vis[s] = tot;
printf("%d\n", temp.val);
}
}
else if(op == 1){
if(vis[s] == 0) {
printf("Invalid\n");
}
else {
auto it = SS.lower_bound(node{vis[s], 0, 0});
if(v == 0) {
printf("%d\n", (*it).val);
}
else if(v == 1) {
it++;
if(it == SS.end()) {
printf("Invalid\n");
}
else {
printf("%d\n", (*it).val);
}
}
else if(v == -1){
if(it == SS.begin()) {
printf("Invalid\n");
}
else {
it--;
printf("%d\n", (*it).val);
}
}
}
}
}
}
return 0;
}