csp复建记录
202104
2.邻域均值
通过题目限制得出 \(x, y\) 的范围,二维前缀和统计即可。
#include <bits/stdc++.h>
using namespace std;
int n, L, r, cnt, a[700][700], sum[700][700];
double ans, t;
int main() {
ios::sync_with_stdio(false);
cin.tie(0); cout.tie(0);
freopen("in","r", stdin);
cin >> n >> L >> r >> t;
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= n; j++) {
cin >> a[i][j];
}
}
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= n; j++) {
sum[i][j] = sum[i - 1][j] + sum[i][j - 1] - sum[i - 1][j - 1] + a[i][j];
}
}
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= n; j++) {
int ex = min(n, i + r), ey = min(n, j + r), sx = max(1, i - r), sy = max(1, j - r);
ans = 1.0 * (sum[ex][ey] - sum[ex][sy - 1] - sum[sx - 1][ey] + sum[sx - 1][sy - 1]) / ((ex - sx + 1) * (ey - sy + 1));
if (ans <= t) cnt++;
}
}
cout << cnt << "\n";
return 0;
}
202109
2.非零段划分
提前记录下来每个值出现过的位置。依次增加 \(p\) 的值,每次找到 \(n\) 个数中等于 \(p\) 的值的位置能产生的贡献(和左右两边 \(0\) 的出现情况有关)。
#include <bits/stdc++.h>
const int N = 5e5 + 5;
const int M = 1e4 + 5;
using namespace std;
int n, ans, maxx, a[N];
vector<int> f[M];
int main() {
ios::sync_with_stdio(false);
cin.tie(0); cout.tie(0);
freopen("in","r", stdin);
cin >> n;
for (int i = 1; i <= n; i++) cin >> a[i];
int cnt = 0;
for (int i = 1; i <= n; i++) {
f[a[i]].push_back(i);
if (a[i] == 0) {
if (cnt > 0) {
ans++;
cnt = 0;
}
}
else cnt++;
}
if (cnt > 0) ans++;
maxx = max(maxx, ans);
for (int i = 1; i <= M - 5; i++) {
for (auto pos : f[i]) {
a[pos] = 0;
if (pos == 1 && a[pos + 1] == 0) ans--;
else if (pos == n && a[pos - 1] == 0) ans--;
else {
if (a[pos - 1] == 0 && a[pos + 1] == 0) ans--;
else if (a[pos - 1] != 0 && a[pos + 1] != 0) ans++;
}
}
maxx = max(maxx, ans);
}
cout << maxx << endl;
return 0;
}
202112
2.序列查询新解
不难发现 \(g(x)\) 每 \(r\) 个增加 \(1\),故可以按段来统计,注意边界情况的讨论。
202203
2.出行计划
由题意不难得到有效条件的区间,差分即可。注意双边不等式的左边可能会小于 \(0\) ,可以通过整体平移的方式(或者和 \(0\) 取 max
的方法)。
#include <bits/stdc++.h>
const int lim = 2e5 + 5;
using namespace std;
int n, m, k, t, c, x, d[lim << 1];
int main() {
ios::sync_with_stdio(false);
cin.tie(0); cout.tie(0);
freopen("in","r", stdin);
cin >> n >> m >> k;
for (int i = 1; i <= n; i++) {
cin >> t >> c;
d[(lim - 5) + t - c - k + 1]++;
d[(lim - 5) + t - k + 1]--;
}
for (int i = 0; i <= (lim - 5) << 1; i++) d[i] += d[i - 1];
for (int i = 1; i <= m; i++) {
cin >> x;
cout << d[(lim - 5) + x] << endl;
}
return 0;
}
202206
2.寻宝!大冒险!
把大地图中每个为 \(1\) 的点记录下来,用相对坐标依次进行比对,统计即可。
#include <bits/stdc++.h>
#define mp make_pair
#define fi first
#define se second
const int N = 100;
using namespace std;
int n, L, S, x, y, ans, b[N][N];
vector<pair<int, int> > a, dir;
map<pair<int, int>, int> mapp;
bool check(pair<int, int> u, pair<int, int> v) {
int dx = u.fi + S + 1, dy = u.se + S + 1;
if (dx > L + 1 || dy > L + 1) return true;
int x = u.fi + v.fi, y = u.se + v.se;
return b[v.fi][v.se] ^ mapp[mp(x, y)];
}
int main() {
ios::sync_with_stdio(false);
cin.tie(0); cout.tie(0);
freopen("in","r", stdin);
cin >> n >> L >> S;
for (int i = 1; i <= n; i++) {
cin >> x >> y;
mapp[mp(x, y)]++;
a.push_back(mp(x, y));
}
for (int i = 0; i <= S; i++) {
for (int j = 0; j <= S; j++) {
cin >> b[i][j];
}
}
for (int j = 0; j <= S; j++) {
for (int i = 0; i < S / 2 + 1; i++) swap(b[i][j], b[S - i][j]);
}
for (int i = 0; i <= S; i++) {
for (int j = 0; j <= S; j++) {
if (i == 0 && j == 0) continue;
dir.push_back(mp(i, j));
}
}
for (auto now : a) {
bool flag = true;
for (auto dxy : dir) {
if (check(now, dxy)) {
flag = false;
break;
}
}
if (flag) ans++;
}
cout << ans << endl;
return 0;
}
3.角色授权
STL
无脑叠 log
, 喜提 70pts
.
#include <bits/stdc++.h>
const int N = 1e5;
using namespace std;
int n, m, q, x, id, id1, id2, ido, idc, idr;
string ch_name, opt, cls, rnm, name, uname, gname, opname, rcls, rname, ss;
map<string, int> mapp, oplist, clslist, rnmlist, ulist, glist;
map<int, int> spe1, spe2, ch_opt[N], ch_cls[N], ch_rnm[N], uright[N], gright[N];
vector<string> ucon[N], gcon[N], ori[N];
int main() {
ios::sync_with_stdio(false);
cin.tie(0); cout.tie(0);
freopen("in","r", stdin);
cin >> n >> m >> q;
while (n--) {
cin >> ch_name;
mapp[ch_name] = ++id;
cin >> x;
while (x--) {
cin >> opt;
if (!oplist[opt]) oplist[opt] = ++ido;
ch_opt[id][oplist[opt]] = 1;
if (opt == "*") spe1[id] = 1;
}
cin >> x;
while (x--) {
cin >> cls;
if (!clslist[cls]) clslist[cls] = ++idc;
ch_cls[id][clslist[cls]] = 1;
if (cls == "*") spe2[id] = 1;
}
cin >> x;
while (x--) {
cin >> rnm;
if (!rnmlist[rnm]) rnmlist[rnm] = ++idr;
ch_rnm[id][rnmlist[rnm]] = 1;
}
}
while (m--) {
cin >> ch_name >> x;
while (x--) {
cin >> ss >> name;
if (ss == "u") {
if (!ulist[name]) ulist[name] = ++id1;
uright[mapp[ch_name]][ulist[name]] = 1;
ucon[ulist[name]].push_back(ch_name);
}
else {
if (!glist[name]) glist[name] = ++id2;
gright[mapp[ch_name]][glist[name]] = 1;
gcon[glist[name]].push_back(ch_name);
}
}
}
while (q--) {
cin >> uname >> x;
if (!ulist[uname]) ulist[uname] = ++id1;
while (x--) {
cin >> gname;
if (!glist[gname]) glist[gname] = ++id2;
ori[ulist[uname]].push_back(gname);
}
bool flag = 0;
cin >> opname >> rcls >> rname;
for (auto ch_name : ucon[ulist[uname]]) {
if (uright[mapp[ch_name]][ulist[uname]]) {
if (ch_opt[mapp[ch_name]][oplist[opname]] || spe1[mapp[ch_name]]) {
if (ch_cls[mapp[ch_name]][clslist[rcls]] || spe2[mapp[ch_name]]) {
if (ch_rnm[mapp[ch_name]].empty() || ch_rnm[mapp[ch_name]][rnmlist[rname]]) {
flag = 1;
}
}
}
}
}
if (flag == 0) {
for (auto gname : ori[ulist[uname]]) {
for (auto ch_name : gcon[glist[gname]]) {
if (gright[mapp[ch_name]][glist[gname]]) {
if (ch_opt[mapp[ch_name]][oplist[opname]] || spe1[mapp[ch_name]]) {
if (ch_cls[mapp[ch_name]][clslist[rcls]] || spe2[mapp[ch_name]]) {
if (ch_rnm[mapp[ch_name]].empty() || ch_rnm[mapp[ch_name]][rnmlist[rname]]) {
flag = 1;
}
}
}
}
}
}
}
cout << flag << endl;
ori[ulist[uname]].clear();
}
return 0;
}
202209
2.何以包邮
70pts
二进制枚举,100pts
完全背包。
#include <bits/stdc++.h>
const int lim = 3e5 + 5;
using namespace std;
int n, m, sum, a[50], f[lim];
int main() {
ios::sync_with_stdio(false);
cin.tie(0); cout.tie(0);
freopen("in","r", stdin);
cin >> n >> m;
for (int i = 1; i <= n; i++) cin >> a[i];
f[0] = 1;
for (int i = 1; i <= n; i++) {
sum += a[i];
for (int j = lim - 5; j >= a[i]; j--) f[j] |= f[j - a[i]];
}
for (int i = m; i <= sum; i++) {
if (f[i]) {
cout << i << endl;
return 0;
}
}
return 0;
}
202212
训练计划
建正图反图分别跑一遍。
#include <bits/stdc++.h>
#define mp make_pair
#define fi first
#define se second
const int N = 5050;
using namespace std;
bool flag;
int n, m, x, maxx, in[N], nin[N], ans[N], a[N];
vector<int> g[N], ng[N];
queue<pair<int, int> > q;
void dfs(int x) {
for (auto to : ng[x]) {
ans[to] = min(ans[to], ans[x] - a[to]);
dfs(to);
}
}
int main() {
ios::sync_with_stdio(false);
cin.tie(0); cout.tie(0);
freopen("in","r", stdin);
cin >> n >> m;
for (int i = 1; i <= m; i++) {
cin >> x;
if (x) {
g[x].push_back(i);
in[i]++;
ng[i].push_back(x);
nin[x]++;
}
}
for (int i = 1; i <= m; i++) cin >> a[i];
for (int i = 1; i <= m; i++) {
if (in[i] == 0) q.push(mp(i, 1));
}
while (!q.empty()) {
auto now = q.front();
q.pop();
int u = now.fi, w = now.se;
ans[u] = w;
maxx = max(maxx, ans[u]);
if (ans[u] + a[u] - 1 > n) flag = 1;
for (auto v : g[u]) {
if (--in[v] == 0) q.push(mp(v, ans[u] + a[u]));
}
}
for (int i = 1; i <= m; i++) cout << ans[i] << (i == m ? "\n" : " ");
memset(ans, 0x3f, sizeof(ans));
if (!flag) {
for (int i = 1; i <= m; i++) {
if (nin[i] == 0) q.push(mp(i, n - a[i] + 1));
}
while (!q.empty()) {
auto now = q.front();
q.pop();
ans[now.fi] = now.se;
dfs(now.fi);
}
for (int i = 1; i <= m; i++) cout << ans[i] << (i == m ? "\n" : " ");
}
return 0;
}
202305
2.矩阵运算
通过交换相乘的次序,化简时间复杂度。
#include <bits/stdc++.h>
const int N = 10500;
const int D = 25;
using namespace std;
int n, d, w[N], q[N][D], k[N][D], v[N][D], tk[D][N];
long long kv[N][N], ans[N][D];
int main() {
ios::sync_with_stdio(false);
cin.tie(0); cout.tie(0);
freopen("in","r", stdin);
cin >> n >> d;
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= d; j++) cin >> q[i][j];
}
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= d; j++) {
cin >> k[i][j];
tk[j][i] = k[i][j];
}
}
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= d; j++) cin >> v[i][j];
}
for (int i = 1; i <= n; i++) cin >> w[i];
//d * n * n * d
for (int k = 1; k <= n; k++) {
for (int i = 1; i <= d; i++) {
for (int j = 1; j <= d; j++) kv[i][j] += 1ll * tk[i][k] * v[k][j];
}
}
//n * d * d * d
for (int k = 1; k <= d; k++) {
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= d; j++) ans[i][j] += 1ll * q[i][k] * kv[k][j];
}
}
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= d; j++) ans[i][j] = 1ll * ans[i][j] * w[i];
}
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= d; j++) cout << ans[i][j] << (j == d ? "\n" : " ");
}
return 0;
}
202309
2.坐标变换(其二)
由于每次操作中的 \(x, y\) 伸缩倍数一样,即若单独考虑经过所有的伸缩操作后,\((x, y)\) 变成了 \((x', y')\), 不难得出 \(\frac{y'}{x'} = \frac{y}{x}\)。同时发现逆时针旋转的操作的角度可以叠加,故用一个前缀积数组存伸缩操作,一个前缀和数组存旋转操作,最终依次直接计算即可。
#include <bits/stdc++.h>
#define mp make_pair
#define fi first
#define se second
const int N = 1e5 + 5;
const int INF = 1 << 30;
using namespace std;
int n, m, opt, i, j;
double x, y, mul[N], sum[N];
int main() {
ios::sync_with_stdio(false);
cin.tie(0); cout.tie(0);
cin >> n >> m;
mul[0] = 1.0;
for (int i = 1; i <= n; i++) {
cin >> opt >> x;
if (opt == 1) {
mul[i] = mul[i - 1] * x;
sum[i] = sum[i - 1];
}
else {
mul[i] = mul[i - 1];
sum[i] = sum[i - 1] + x;
}
}
while (m--) {
cin >> i >> j >> x >> y;
double nowk = mul[j] / mul[i - 1], nowth = sum[j] - sum[i - 1], ncos = cos(nowth), nsin = sin(nowth);
printf("%lf %lf\n", nowk * (x * ncos - y * nsin), nowk * (x * nsin + y * ncos));
}
return 0;
}