3.21校赛
A题目
题意
给出字符串,以标点符号为界,写成一个大写一个小写的形式
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int MOD = 100003;
const int MAX = 1e3 + 10;
int main() {
string str;
cin >> str;
int len = str.length();
int cnt = 0;
for(int i = 0; i < len; i++) {
if(!isalpha(str[i])) {
cnt = 0;
printf("%c", str[i]);
}
else {
cnt++;
if(cnt % 2) printf("%c", toupper(str[i]));
else printf("%c", tolower(str[i]));
}
}
}
H题目
题意
给n,S,(1 <= n <= 1000, 0 <= S <= 3000)问又多少中分法,使得数组a大小为n(ai为非负数,且不递减,总和为S),取模,MOD = 998255353
题解
其实,对于n个数,我只要取出每个ai的个数,就好了,因为排序规定了,
即对于不同的n个数,对于答案贡献为1,
那么,就可以忽略 数组内部不递减,这个条件
那么,问题就等价于S个数,分为n组,有几种分法
这就是计数DP板子题
啊,举个例子,S = 15, n = 5
1 2 3 4 5 和 5 4 3 2 1 是一样的(或者可以认为后面的忽略掉了
1 2 2 5 5 是不一样的
那只要考虑取出的数是不一样的排列,ans++
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int MOD = 998244353;
const int MAX = 5e3 + 10;
int dp[MAX][MAX];
int main() {
int n, V;
scanf("%d%d", &n, &V);
for(int i = 1; i <= n; i++) dp[i][0] = 1;
for(int i = 1; i <= n; i++) {
for(int j = 1; j <= V; j++) {
if(j >= i) dp[i][j] = (dp[i - 1][j] + dp[i][j - i]) % MOD;
else dp[i][j] = dp[i - 1][j] % MOD;
}
}
printf("%d\n", dp[n][V] % MOD);
}
I题目
题意
给出两个字符串s,t,以及每一秒变化的数数组a, b(变化是指每一秒ai对应的si字典序加ai,but保证为小写字母(‘z’下面又是’a’)),问q次询问(q<=1e6),变化t(t<=1e18),问每次变化的最长公共子序列多长,s,t字符串字长1e3
题解
其实很简单,因为我注意到了t一定是要mod26的,26次以后就是一个循环
那么只要预处理一下就好了
我应该坚定的,LCS复杂度O(n^2),那么就1e6了,不可能再*q次询问的(主要是我记得好像有LCSo(n)的解法,误导我自己了,就算是这样1e9也不一定过的了
不对,1e9是铁T
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int MOD = 100003;
const int MAX = 1e3 + 10;
char s[MAX], t[MAX];
int dp[30][MAX][MAX];
int len1, len2;
int a[MAX], b[MAX];
char s1[MAX], t1[MAX];
void solve() {
for(int k = 0; k < 26; k++) {
for(int i = 1; i <= len1; i++) s1[i] = (char) ('a' + (s[i] - 'a' + k * a[i]) % 26);
for(int i = 1; i <= len2; i++) t1[i] = (char) ('a' + (t[i] - 'a' + k * b[i]) % 26);
for(int i = 1; i <= len1; i++) {
for(int j = 1; j <= len2; j++) {
if(s1[i] == t1[j]) dp[k][i][j] = dp[k][i - 1][j - 1] + 1;
else dp[k][i][j] = max(dp[k][i - 1][j], dp[k][i][j - 1]);
}
}
}
}
int main() {
int n, m;
scanf("%d%d\n", &n, &m);
scanf("%s\n", s + 1);
scanf("%s\n", t + 1);
len1 = strlen(s + 1);
len2 = strlen(t + 1);
for(int i = 1; i <= len1; i++) scanf("%d", &a[i]);
for(int i = 1; i <= len2; i++) scanf("%d", &b[i]);
solve();
ll q;
scanf("%lld", &q);
while(q--) {
ll t;
scanf("%lld", &t);
printf("%d\n", dp[t % 26][len1][len2]);
}
}
J题目
题意
一个开关,有p(p = n / 1e4)的概率打卡,可以操作无限次,问最大的概率是多少
题解
p >= 0.5 ==> ans = p;
p >= 0 && p < 0.5 ==> ans = 0.5;
p = 0 ==> ans = 0;
《大胆猜测,小心求证》
(可以打一下前几项的概率,输入不同的值,其实是满足猜测的,就试试
《打表找规律》
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int MOD = 100003;
const int MAX = 1e3 + 10;
int main() {
int T;
scanf("%d", &T);
while(T--) {
double n;
scanf("%lf", &n);
double ans = 0;
if(n == 0) ans = 0;
else if(n >= 5000) ans = n / 10000;
else ans = 0.5;
printf("%.6lf\n", ans);
}
}
C题目
题意
有n个人,每个人权重xi, 可以玩ai次,如果输了,就直接淘汰,如果两个人Pk,得到的权值li为xi ^ xj + xi + xj,问权值最大为多少
题解
可以将一个人分成两个点思考,对于i点所有可以击败的点j,连边流量为1,权值为xi ^ xj + xi + xj,源点S流向i点,如果i是最大的点,那么他可以赢ai次,流量为ai,否则一定会被打败一次,流量为ai - 1
对于点i来说,流入的代表可以赢的场次,能够流通的点,代表可以打败,上面还有费用权重,对于被打败的j点来说,流出的流量为1,代表输了一次就下场了
这样可以求最小费用流,问题是最大费用流,那么取反。
tips
我竟然不知道,^ 的 优先级 比 + 小(我还以为是一样的)
一
个
没
有
用
到
的
却
感
觉
比
较
有
用
的
知
识
点
:
a
+
b
=
2
×
(
a
&
b
)
+
a
x
o
r
b
;
\color{blue}一个没有用到的却感觉比较有用的知识点: a + b = 2 \times\ (a \& b) + a \ xor\ b;
一个没有用到的却感觉比较有用的知识点:a+b=2× (a&b)+a xor b;
a
x
o
r
b
+
a
&
b
=
a
∣
b
\color{blue}a\ xor \ b + a \& b = a | b
a xor b+a&b=a∣b
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll MAX = 2e6 + 10;
#define SZ(v) (int)v.size()
#define pii pair<ll,ll>
const ll INF = 0x3f3f3f3f;
const ll MAXN = 2e6 + 10;
struct MCMF {
struct Edge {
ll v, cap, cost, rev;
Edge(ll v, ll cap, ll cost, ll rev):v(v),cap(cap),cost(cost),rev(rev){}
};
ll flow, cost, s, t, n;
ll dist[MAXN], H[MAXN], pv[MAXN], pe[MAXN];
std::vector<Edge> G[MAXN];
bool dijkstra() {
std::priority_queue<pii, std::vector<pii>, std::greater<pii> > q;
std::fill(dist, dist + n + 1, INF);
dist[s] = 0; q.push({0, s});
while (!q.empty()) {
pii x = q.top(); q.pop();
ll &u = x.second;
if (dist[u] < x.first) continue;
for (int i = 0; i < SZ(G[u]); ++i) {
Edge &e = G[u][i];
ll &v = e.v;
pii y(dist[u] + e.cost + H[u] - H[v], v);
if (e.cap > 0 && dist[v] > y.first) {
dist[v] = y.first;
pe[v] = i, pv[v] = u;
q.push(y);
}
}
}
if (dist[t] == INF) return false;
for (int i = 0; i <= n; ++i) H[i] += dist[i];
ll f = INF;
for (int v = t; v != s; v = pv[v]) f = std::min(f, G[pv[v]][pe[v]].cap);
flow += f;
cost += f * H[t];
for (int v = t; v != s; v = pv[v]) {
Edge &e = G[pv[v]][pe[v]];
e.cap -= f;
G[v][e.rev].cap += f;
}
return true;
}
void solve(int s, int t) {
this->s = s, this->t = t;
flow = cost = 0;
std::fill(H, H + n + 1, 0);
while (dijkstra());
}
void init(int n) {
this->n = n;
for (int i = 0; i <= n; ++i) G[i].clear();
}
void add_edge(ll u, ll v, ll cap, ll cost) {
G[u].push_back(Edge(v, cap, cost, SZ(G[v])));
G[v].push_back(Edge(u, 0, -cost, SZ(G[u]) - 1));
}
} mcmf;
ll x[MAX];
ll a[MAX];
int main() {
ll n;
scanf("%lld", &n);
ll s = 2 * n + 1, t = s + 1;
mcmf.init(t);
int posmax = 0;
ll maxx = -1;
for(int i = 0; i < n; i++) {
scanf("%lld%lld", &x[i], &a[i]);
if (x[i] > maxx) {
maxx = x[i];
posmax = i;
}
mcmf.add_edge(s, i, a[i] - 1, 0);
mcmf.add_edge(i + n, t, 1, 0);
}
mcmf.add_edge(s, posmax, 1, 0);
for(int i = 0; i < n; i++) {
for(int j = 0; j < n; j++) {
if(x[i] > x[j]) {
ll cost = (x[i] ^ x[j]) + (x[i] + x[j]);
//ll cost = (x[i] | x[j]) * 2;
mcmf.add_edge(i, j + n, 1, -cost);
}
}
}
mcmf.solve(s, t);
ll ans = mcmf.cost;
printf("%lld\n", -ans);
}
个人总结
我发现了我的舒适点, 还有薄弱点( 这周发现的)
即绕好几个弯的思维题( 优化题面, 简化问题) , ( 校赛证明DP 我还是可以出的嘛
我的缺点是读题太差( 且不是很愿意读题, 开新的题目, 在后两个小时最为明显)
后劲不足, 两小时后就不去思考了
图论这块差( 按照知识点来说
团队总结
( 校赛第七名, 除去打星
总的来说, 比较幸运。
( 我们前6 题, 只PE 了一次( 十分可惜, 如果正式比赛有热身赛, 就可以试错规避) , 罚时较少
后面出了G 题, 属于较难题目, 且比赛后半段思维感觉不是很活跃
优点是罚时少, 简单题目出题比较稳且快
缺点是, 确实能力有限, 难题不会写, 较高强度思考使得脑子太快糊掉了( 要多进行长时间的训练
经验:
不一定要跟榜, 可以先随意开, 有思路就试一试, 就比如说开了H 题, 果断试了一下, 过了( 感觉信心也+ + 了
注重cin cout 的关闭同步流, 不能因为这个T , 造成罚时
交流大声一点, 确保队友有效交流
对于不确定的题目( 指的是不能严格证明, but 大致推测除了规律的题目) , 和队友交流一下, 感觉没有问题, 就冲
善用打表看规律( 适于是在出不了题目的情况), 其实E 题会发现3 * c * c 无解, 2 * c * c 解是c * c 的解法+ 1