A.実行
問題の意味:
雲がすべて移動させることができる\(1 \) Mまたは\(K \)メートルで移動するように求め数メートル\([L、R] \ ) 数の範囲内の数です。
アイデア:
\(DP [I]が[0/1] \)セクションを表し\(Iは\) mは、によって得られる\(\ 1)メートルのよう以上\(K \)方法上のM、配達彼らは、プッシュすることができます。
コード:
#include <bits/stdc++.h>
using namespace std;
#define N 100010
const int p = 1e9 + 7;
int f[N][2], g[N];
int q, k, l, r;
void add(int &x, int y) {
x += y;
if (x >= p) {
x -= p;
}
}
int main() {
scanf("%d%d", &q, &k);
memset(f, 0, sizeof f);
f[0][0] = 1;
for (int i = 0; i <= 100000; ++i) {
add(f[i + 1][0], (f[i][0] + f[i][1]) % p);
if (i + k <= 100000) {
add(f[i + k][1], f[i][0]);
}
}
memset(g, 0, sizeof g);
for (int i = 1; i <= 100000; ++i) {
g[i] = g[i - 1];
add(g[i], f[i][0]);
add(g[i], f[i][1]);
}
while (q--) {
scanf("%d%d", &l, &r);
printf("%d\n", (g[r] - g[l - 1] + p) % p);
}
return 0;
}
D. monrey
質問の意味:
そこ\(N \)からアイテム番目の\(1 \)に\(N \) 、それぞれが無制限の持っているアイテムを、購入または売却することができる唯一の項目の最大を運ぶことができます誰が、アクセスするためには、お金、そして最終的にはほとんどどのくらいの利益を尋ねました。
アイデア:
売買合併時に、マイナスの所得が購入し、販売することですが、収入を増やす2つのスタックを維持する、横断することです考えてみましょう\(私は\)項目目を。
- 時間が購入したとき、最も高い販売操作の1つ前の収入を探している場合、または直接購入します。
- そして時間が販売されているときならば、見つけるために取る前に、最高の営業利益の1を買いました。
コード:
#include <bits/stdc++.h>
using namespace std;
#define ll long long
#define N 100010
int n, a[N];
struct node {
ll tot; int cnt;
node() {}
node (ll tot, int cnt) : tot(tot), cnt(cnt) {}
bool operator < (const node &other) const {
if (tot == other.tot) {
return cnt > other.cnt;
}
return tot < other.tot;
}
};
int main() {
int T; scanf("%d", &T);
while (T--) {
scanf("%d", &n);
for (int i = 1; i <= n; ++i) {
scanf("%d", a + i);
}
//0表示上一次操作是买入
//1表示上一次操作是卖出
priority_queue <node> pq[2];
node res = node(0, 0);
pq[0].push(node(-a[1], 1));
node t1, t2;
for (int i = 2; i <= n; ++i) {
pq[0].push(node(-a[i], 1));
if (!pq[0].empty()) {
t1 = pq[0].top();
pq[1].push(node(t1.tot + a[i], t1.cnt + 1));
}
if (!pq[1].empty()) {
t2 = pq[1].top();
pq[0].push(node(t2.tot - a[i], t2.cnt + 1));
}
if (!pq[1].empty()) {
res = max(res, pq[1].top());
}
}
printf("%lld %d\n", res.tot, res.cnt);
}
return 0;
}
J.ファーム
問題の意味:
中\(N \ CDOTメートル\)農地で、そこに\(N \ CDOTメートル\)の木の植物、各プラントセクションのみをキャストすることができます([I] [J \を ] \) があり、肥料\(T \)の操作、各操作がされる(X_1、Y_1、X_2 \ Y_2 \) 作物が最初に矩形内に投与される\(K_I \)肥料、
一度作物に適用される最初のない\(A [I] [J] \)肥料は、それがすぐに死んでしまいます。
Q.最後作物の死の数。
アイデア:
考える:
=作物の飼料の数\([I] [J ] \) 数+肥料の肥料肥料肥料他の種類の数。
まず、すべての作物の2次元差分受精の総数を決定しました。
その後のように実行\(K_I \)分類、二次元BITと二次元プレフィックスのメンテナンスは示している(K_I \)\操作下肥料植物の数。
次いで、初期値列挙\(K_I \)を全ての作物において、それは肥料との合計数と判断された\(K_I \)飼料肥料の数が等しい、等しくないがハングアップ。
時間計算:\(\ mathcal {O}(NM + T \ CDOTログ(N)\ CDOTログ(M))\)
コードワン:
#include <bits/stdc++.h>
using namespace std;
#define N 1000010
#define pii pair <int, int>
#define fi first
#define se second
int n, m, q;
struct node {
int x[2], y[2];
node() {}
node(int x1, int y1, int x2, int y2) {
x[0] = x1; x[1] = x2;
y[0] = y1; y[1] = y2;
}
};
vector < vector <pii> > a;
vector < vector <node> > b;
struct BIT {
vector < vector <int> > a;
void init() {
a.clear();
a.resize(n + 1);
for (int i = 0; i < n + 1; ++i) {
a[i].resize(m + 1);
}
}
void update(int x, int y, int v) {
for (int i = x; i <= n; i += i & -i) {
for (int j = y; j <= m; j += j & -j) {
a[i][j] += v;
}
}
}
void update(int x1, int y1, int x2, int y2, int v) {
update(x1, y1, v);
update(x2 + 1, y2 + 1, v);
update(x1, y2 + 1, -v);
update(x2 + 1, y1, -v);
}
int query(int x, int y) {
int res = 0;
for (int i = x; i > 0; i -= i & -i) {
for (int j = y; j > 0; j -= j & -j) {
res += a[i][j];
}
}
return res;
}
}bit;
void read(int &x) {
x = 0; char ch;
while (!isdigit(ch = getchar()));
while (isdigit(ch)) {
x = x * 10 + ch - '0';
ch = getchar();
}
}
int main() {
while (scanf("%d%d%d", &n, &m, &q) != EOF) {
a.clear();
a.resize(n * m + 1);
b.clear();
b.resize(n * m + 1);
bit.init();
for (int i = 1; i <= n; ++i) {
for (int j = 1, x; j <= m; ++j) {
read(x);
a[x].emplace_back(i, j);
}
}
for (int i = 1, k, x1, y1, x2, y2; i <= q; ++i) {
read(x1); read(y1); read(x2); read(y2); read(k);
b[k].push_back(node(x1, y1, x2, y2));
bit.update(x1, y1, x2, y2, 1);
}
int res = 0;
for (int i = 1; i <= n * m; ++i) {
for (auto it : b[i]) {
bit.update(it.x[0], it.y[0], it.x[1], it.y[1], -1);
}
for (auto it : a[i]) {
if (bit.query(it.fi, it.se) != 0) {
++res;
}
}
for (auto it : b[i]) {
bit.update(it.x[0], it.y[0], it.x[1], it.y[1], 1);
}
}
printf("%d\n", res);
}
return 0;
}
:2思考
であるたびに肥料を加え考えてみましょう\(K_I \)の代わりに、1、最終的な作物でない場合は死んで、その値がされなければならない\([I] [J ] \ CDOT 数の施肥\)。
しかし、これは重みが素数にマップすることができ、簡単にカードです。
コードII:
#include <bits/stdc++.h>
using namespace std;
#define ll long long
#define N 15500010
int prime[1000010], tot;
bool check[N];
void init() {
tot = 0;
memset(check, 0, sizeof check);
for (int i = 2; i < N; ++i) {
if (!check[i]) {
prime[++tot] = i;
if (tot >= 1000000) break;
}
for (int j = 1; j <= tot; ++j) {
if (1ll * i * prime[j] >= N) break;
check[i * prime[j]] = 1;
if (i % prime[j] == 0) {
break;
}
}
}
}
int n, m, q;
vector <vector<int>> a, c;
vector <vector<ll>> b;
template <class T>
void up(vector <vector<T>> &vec, int x1, int y1, int x2, int y2, int v) {
vec[x1][y1] += v;
vec[x2 + 1][y2 + 1] += v;
vec[x1][y2 + 1] -= v;
vec[x2 + 1][y1] -= v;
}
template <class T>
void work(vector <vector<T>> &vec) {
for (int i = 1; i <= n; ++i) {
for (int j = 1; j <= m; ++j) {
vec[i][j] += vec[i - 1][j] + vec[i][j - 1] - vec[i - 1][j - 1];
}
}
}
int main() {
init();
random_shuffle(prime + 1, prime + 1 + tot);
while (scanf("%d%d%d", &n, &m, &q) != EOF) {
a.clear(); a.resize(n + 2, vector <int> (m + 2, 0));
b.clear(); b.resize(n + 2, vector <ll> (m + 2, 0));
c.clear(); c.resize(n + 2, vector <int> (m + 2, 0));
for (int i = 1; i <= n; ++i) {
for (int j = 1; j <= m; ++j) {
scanf("%d", &a[i][j]);
}
}
int x[2], y[2], k;
while (q--) {
scanf("%d%d%d%d%d", x, y, x + 1, y + 1, &k);
up(b, x[0], y[0], x[1], y[1], prime[k]);
up(c, x[0], y[0], x[1], y[1], 1);
}
work(b); work(c);
int res = 0;
for (int i = 1; i <= n; ++i) {
for (int j = 1; j <= m; ++j) {
if (b[i][j] != c[i][j] * prime[a[i][j]]) {
++res;
}
}
}
printf("%d\n", res);
}
return 0;
}
3思考: