NOIP模拟赛记录
2023.10.23 比赛记录
A. 公园
直接dijkstra
即可
可爱的code捏
#include <bits/stdc++.h>
using namespace std;
#define int long long
#define ull unsigned long long
#define ALL(a) (a).begin(), (a).end()
#define pb push_back
#define mk make_pair
#define pii pair<int, int>
#define pis pair<int, string>
#define sec second
#define fir first
#define sz(a) int((a).size())
#define Yes cout << "Yes" << endl
#define YES cout << "YES" << endl
#define No cout << "No" << endl
#define NO cout << "NO" << endl
#define debug(x) cerr << #x << ": " << x << endl
#define mms(arr, n) memset(arr, n, sizeof(arr))
#define rep(i, a, n) for (int i = (a); i <= (n); ++i)
#define per(i, n, a) for (int i = (n); i >= (a); --i)
int max(int a, int b) {
if (a > b)
return a;
return b;
}
int min(int a, int b) {
if (a < b)
return a;
return b;
}
const int INF = 0x3f3f3f3f3f3f3f3f;
const int MOD = 1000000007;
const int N = 1e5 + 10;
// bool st;
int n, m, c;
vector<pii> g[N];
int dis[N];
bool vis[N];
int sum = 0;
int res, cnt = 0;
// bool en;
void dijkstra() {
memset(dis, 0x3f, sizeof(dis));
priority_queue<pii, vector<pii>, greater<pii>> q;
q.push({ 0, 1 });
dis[1] = 0;
while (!q.empty()) {
auto [ds, x] = q.top();
q.pop();
if (ds != dis[x])
continue;
for (auto [v, w] : g[x])
if (vis[v])
sum -= w;
vis[x] = true;
cnt++;
// cerr << x << ' ' << ds << ' ' << cnt << ' ' << sum << ' ' << ds * cnt + sum << endl;
res = min(res, ds * c + sum);
for (auto [v, w] : g[x]) {
if (dis[v] > dis[x] + w) {
dis[v] = dis[x] + w;
q.push({ dis[v], v });
}
}
}
}
void solve() {
cin >> n >> m >> c;
rep(i, 1, m) {
int u, v, w;
cin >> u >> v >> w;
g[u].push_back({ v, w });
g[v].push_back({ u, w });
sum += w;
}
res = sum;
dijkstra();
cout << res << endl;
}
signed main() {
freopen("park.in", "r", stdin);
freopen("park.out", "w", stdout);
// cerr<<(&en-&st)/1024.0/1024.0<<endl;
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int testcase = 1;
// cin >> testcase;
while (testcase--) solve();
return 0;
}
B. 括号
考虑这样的贡献,每个右括号,考虑先找到一个左括号与它匹配,
此时考虑在这个匹配左侧加上一个括号序列
可以用一个stack
记录剩下 \(x\) 个时的贡献
可爱的code捏
#include <bits/stdc++.h>
using namespace std;
#define int long long
#define ull unsigned long long
#define ALL(a) (a).begin(), (a).end()
#define pb push_back
#define mk make_pair
#define pii pair<int, int>
#define pis pair<int, string>
#define sec second
#define fir first
#define sz(a) int((a).size())
#define Yes cout << "Yes" << endl
#define YES cout << "YES" << endl
#define No cout << "No" << endl
#define NO cout << "NO" << endl
#define debug(x) cerr << #x << ": " << x << endl
#define mms(arr, n) memset(arr, n, sizeof(arr))
#define rep(i, a, n) for (int i = (a); i <= (n); ++i)
#define per(i, n, a) for (int i = (n); i >= (a); --i)
int max(int a, int b) {
if (a > b)
return a;
return b;
}
int min(int a, int b) {
if (a < b)
return a;
return b;
}
const int INF = 0x3f3f3f3f3f3f3f3f;
const int MOD = 1000000007;
const int N = 1e7 + 10;
// bool st;
int n, x, y, z, m[2], c[N];
int cnt = 0;
int sum = 0;
ull res = 0;
stack<pii> st;
// bool en;
void solve() {
cin >> n >> x >> y >> z >> m[0] >> m[1] >> c[1] >> c[2];
// // cerr << c[1] << ' ' << c[2] << ' ';
rep(i, 3, n) {
c[i] = (c[i - 1] * x + c[i - 2] * y + z) % m[(i & 1) ^ 1] + 1;
// cerr << c[i] << ' ';
}
cnt = 0;
rep(i, 1, n) {
if (i & 1) {
cnt += c[i];
continue;
}
res += min(cnt, c[i]);
while (!st.empty() && st.top().first > cnt - c[i]) {
res += st.top().second;
st.pop();
}
if (cnt < c[i])
cnt = 0;
else {
cnt -= c[i];
if (st.empty() || st.top().first != cnt)
st.push({ cnt, 1 });
else {
res += st.top().second;
st.top().second++;
}
}
}
// cerr << endl;
cout << res << endl;
}
signed main() {
freopen("brackets.in", "r", stdin);
freopen("brackets.out", "w", stdout);
// cerr << (&en - &st) / 1024.0 / 1024.0 << endl;
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int testcase = 1;
// cin >> testcase;
while (testcase--) solve();
return 0;
}
C. 学校
注意到一个重要的条件 \(a_i \neq a_j\)
考虑 \(dp_i\) 表示选择第 \(i\) 位且 \(i\) 选择的方案数
枚举 \(i,j\) 表示最后两个选中的位置,考虑如何 \(O(1)\) 的算剩下的 \(2\) 个
可以用前缀和做,即 \(sum_{i,j}\) 表示到 \(i\) 位, 选择 \(2\) 个的 \(\oplus\) 值为 \(j\) 的方案数
可爱的code捏
#include <bits/stdc++.h>
using namespace std;
#define int long long
#define ull unsigned long long
#define ALL(a) (a).begin(), (a).end()
#define pb push_back
#define mk make_pair
#define pii pair<int, int>
#define pis pair<int, string>
#define sec second
#define fir first
#define sz(a) int((a).size())
#define Yes cout << "Yes" << endl
#define YES cout << "YES" << endl
#define No cout << "No" << endl
#define NO cout << "NO" << endl
#define debug(x) cerr << #x << ": " << x << endl
#define mms(arr, n) memset(arr, n, sizeof(arr))
#define rep(i, a, n) for (int i = (a); i <= (n); ++i)
#define per(i, n, a) for (int i = (n); i >= (a); --i)
int max(int a, int b) {
if (a > b)
return a;
return b;
}
int min(int a, int b) {
if (a < b)
return a;
return b;
}
const int INF = 0x3f3f3f3f3f3f3f3f;
const int MOD = 998244353;
const int N = 5e3 + 10;
// bool st;
int n, m, s;
int a[N];
int dp[N], sum[N][N];
int res = 0;
// bool en;
void solve() {
cin >> n >> m >> s;
rep(i, 1, n) cin >> a[i];
rep(i, 1, n) {
dp[i] = 1;
rep(j, 0, (1 << m)) sum[i][j] = sum[i - 1][j];
rep(j, 1, i - 1) {
int val = ((dp[j] - sum[j - 1][s ^ a[i] ^ a[j]]) % MOD + MOD) % MOD;
(dp[i] += val) %= MOD;
(sum[i][a[i] ^ a[j]] += val) %= MOD;
}
(res += dp[i]) %= MOD;
}
cout << res << endl;
}
signed main() {
freopen("school.in", "r", stdin);
freopen("school.out", "w", stdout);
// cerr<<(&en-&st)/1024.0/1024.0<<endl;
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int testcase = 1;
// cin >> testcase;
while (testcase--) solve();
return 0;
}
D. 运算
考场想了个线段树优化建图,其实没必要,因为常数过大,在大多数数据下不如暴力
明显应该把操作逆过来,即从 \(0\) 倒推
可以将第一次操作算成加法,然后每次除一下再减一下
除法可以在一开始预处理,即 \((i\times d)\mod{n} \rightarrow i\) 建边
每个点的答案在第一次访问时就确定了,而且只会在第一次访问时向别的点贡献
此时,其实就是一个区间删除,区间查询剩下的数
就可以并查集维护每个点右边的第一个还没被访问的点,暴力扩展即可
有一点点卡常 加个快读就过了
可爱的code捏
#include <bits/stdc++.h>
using namespace std;
// #define int long long
#define ull unsigned long long
#define ALL(a) (a).begin(), (a).end()
#define pb push_back
#define mk make_pair
#define pii pair<int, int>
#define pis pair<int, string>
#define sec second
#define fir first
#define sz(a) int((a).size())
#define Yes cout << "Yes" << endl
#define YES cout << "YES" << endl
#define No cout << "No" << endl
#define NO cout << "NO" << endl
#define debug(x) cerr << #x << ": " << x << endl
#define mms(arr, n) memset(arr, n, sizeof(arr))
#define rep(i, a, n) for (int i = (a); i <= (n); ++i)
#define per(i, n, a) for (int i = (n); i >= (a); --i)
int max(int a, int b) {
if (a > b)
return a;
return b;
}
int min(int a, int b) {
if (a < b)
return a;
return b;
}
const int INF = 0x3f3f3f3f;
const int MOD = 1000000007;
const int N = 1e6 + 10;
// #define DEBUG 1 // 调试开关
struct IO {
#define MAXSIZE (1 << 20)
#define isdigit(x) (x >= '0' && x <= '9')
char buf[MAXSIZE], *p1, *p2;
char pbuf[MAXSIZE], *pp;
#if DEBUG
#else
IO() : p1(buf), p2(buf), pp(pbuf) {}
~IO() { fwrite(pbuf, 1, pp - pbuf, stdout); }
#endif
char gc() {
#if DEBUG // 调试,可显示字符
return getchar();
#endif
if (p1 == p2)
p2 = (p1 = buf) + fread(buf, 1, MAXSIZE, stdin);
return p1 == p2 ? ' ' : *p1++;
}
bool blank(char ch) { return ch == ' ' || ch == '\n' || ch == '\r' || ch == '\t'; }
template <class T>
void read(T &x) {
double tmp = 1;
bool sign = 0;
x = 0;
char ch = gc();
for (; !isdigit(ch); ch = gc())
if (ch == '-')
sign = 1;
for (; isdigit(ch); ch = gc()) x = x * 10 + (ch - '0');
if (ch == '.')
for (ch = gc(); isdigit(ch); ch = gc()) tmp /= 10.0, x += tmp * (ch - '0');
if (sign)
x = -x;
}
void read(char *s) {
char ch = gc();
for (; blank(ch); ch = gc())
;
for (; !blank(ch); ch = gc()) *s++ = ch;
*s = 0;
}
void read(char &c) {
for (c = gc(); blank(c); c = gc())
;
}
void push(const char &c) {
#if DEBUG // 调试,可显示字符
putchar(c);
#else
if (pp - pbuf == MAXSIZE)
fwrite(pbuf, 1, MAXSIZE, stdout), pp = pbuf;
*pp++ = c;
#endif
}
template <class T>
void write(T x) {
if (x < 0)
x = -x, push('-'); // 负数输出
static T sta[35];
T top = 0;
do {
sta[top++] = x % 10, x /= 10;
} while (x);
while (top) push(sta[--top] + '0');
}
template <class T>
void write(T x, char lastChar) {
write(x), push(lastChar);
}
} io;
// bool st;
int n, d, l, r, q;
vector<int> g[N];
int dis[N];
queue<int> que;
// bool en;
struct Union {
int fa[N];
void init() { rep(i, 0, n) fa[i] = i; }
int get(int x) {
if (fa[x] == x)
return x;
return fa[x] = get(fa[x]);
}
void merge(int x, int y) { fa[get(x)] = get(y); }
void tag(int x) { merge(x, x + 1); }
} uni;
void solve() {
memset(dis, 0x3f, sizeof(dis));
io.read(n);
io.read(d);
io.read(l);
io.read(r);
io.read(q);
uni.init();
rep(i, 0, n - 1) g[i].clear();
rep(i, 0, n - 1) g[1ll * i * d % n].push_back(i);
rep(i, n - r, n - l) {
dis[i] = 0;
uni.tag(i);
que.push(i);
}
while (!que.empty()) {
int x = que.front();
que.pop();
for (auto v : g[x]) {
int st = (v - r + n) % n, en = (v - l + n) % n;
if (st <= en) {
for (int i = uni.get(st); i <= en; i = uni.get(i)) {
dis[i] = dis[x] + 1;
uni.tag(i);
que.push(i);
}
} else {
for (int i = uni.get(0); i <= en; i = uni.get(i)) {
dis[i] = dis[x] + 1;
uni.tag(i);
que.push(i);
}
for (int i = uni.get(st); i < n; i = uni.get(i)) {
dis[i] = dis[x] + 1;
uni.tag(i);
que.push(i);
}
}
}
}
while (q--) {
int x;
io.read(x);
if (dis[x] >= INF) {
io.push('-');
io.push('1');
io.push('\n');
} else {
io.write(dis[x], '\n');
}
}
}
signed main() {
freopen("calculator.in", "r", stdin);
freopen("calculator.out", "w", stdout);
// cerr<<(&en-&st)/1024.0/1024.0<<endl;
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int testcase = 1;
io.read(testcase);
while (testcase--) solve();
return 0;
}
2023.10.23模拟赛总结
T2赛场做法假了,没对拍
T3没有注意到重要的 \(a_i \neq a_j\) 的条件
T4注意线段树常数很大,不如暴力,\(10^6\) 应该优先考虑 \(\mathcal{O(n)}\) 做法
标签:ch,return,NOIP,记录,int,long,push,模拟,define From: https://www.cnblogs.com/xiaruize/p/17782596.html