H-World Finals
原题:H-World Finals_2024牛客暑期多校训练营1 (nowcoder.com)https://ac.nowcoder.com/acm/contest/81596/H
题目大意:
有两场World Finals同时举办,每场都有若干出线队伍,两场出线名单可能有重复的队伍,而一个队伍只能选择其中的一场参加,然后每场比赛的每支队伍都有一个预测成绩(过题数+ 罚时)lzr010506在两场World Finals 都出线了,他想知道如果所有队伍的最终成绩就是预测成绩,并且可以任意分配两场都出线了队伍的比赛场次的选择,他们队最高可能的排名是多少(1 ≤ number of teams ≤ 10^5)
题解:
两种情况:1、“lzr010506”参加第一场,其他比他强的在第二场;2、“lzr010506”参加第二场,其他比他强的在第一场。两种情况取最优即可。
代码片段:
struct t {
string name;
int problem;
int time;
};
bool cmp(t x, t y) {
if (x.problem == y.problem) return x.time < y.time;
return x.problem > y.problem;
}
map<string, int> a;
int m, n, e1, i, j, w1, w2, w, ans1, ans2, sum;
string e[100005];
void solve() {
cin >> n;
vector<t> c(n);
for (i = 0; i < n; i++) {
cin >> c[i].name >> c[i].problem >> c[i].time;
a[c[i].name]++;
}
cin >> m;
vector<t> d(m);
for (i = 0; i < m; i++) {
cin >> d[i].name >> d[i].problem >> d[i].time;
a[d[i].name]++;
}
for (auto i: a) {
if (i.second == 2) {
e[e1] = i.first;
e1++;
}
}
sort(c.begin(), c.end(), cmp);
sort(d.begin(), d.end(), cmp);
for (i = 0; i < n; i++) {
if (c[i].name == "lzr010506") {
w1 = i;
break;
}
}
for (i = 0; i < m; i++) {
if (d[i].name == "lzr010506") {
w2 = i;
break;
}
}
unordered_set<string> res(e, e + e1);
for (i = 0; i < w1; i++) {
if (res.count(c[i].name)) {
ans1++;
}
}
for (i = 0; i < w2; i++) {
if (res.count(d[i].name)) {
ans2++;
}
}
sum = min(w1 - ans1, w2 - ans2);
cout << sum + 1 << endl;
}
C-Sum of Suffix Sums
C-Sum of Suffix Sums_2024牛客暑期多校训练营1 (nowcoder.com)https://ac.nowcoder.com/acm/contest/81596/C
题目大意:
一个初始为空的非负整数序列,支持q次操作,每次操作移除末尾的若干个整数,然后在末尾加入一个整数v,每次操作后输出当前序列所有后缀和的总和,答案对1e9+7取模(1 ≤ q ≤ 5×1e5, 0 ≤ v ≤ 1e9)
题解:
ai 会出现在所有起始位置≤i的后缀和里,在总和里出现i次,总和就是i×ai
代码:
void solve() {
int q;
cin >> q;
vector<ll> pre;
long long sum = 0;
while (q--) {
int t;
ll v;
cin >> t >> v;
while (t-- > 0 && !pre.empty()) {
sum = (sum - pre.back() + MOD) % MOD;
pre.pop_back();
}
sum = (sum + v) % MOD;
if (!pre.empty()) {
pre.push_back((pre.back() + v) % MOD);
} else {
pre.push_back(v);
}
cout << sum << endl;
}
}
A-A Bit Common
原题:A-A Bit Common_2024牛客暑期多校训练营1 (nowcoder.com)https://ac.nowcoder.com/acm/contest/81596/A
题目大意:
有多少长为n的元素在[0,2^m)的整数序列满足:存在一个非空子序列的AND和是1,答案对输入的正整数q取模(1≤n,m≤5000),1≤q≤1e9。
思路:
首先注意q不一定是质数!!!
AND和为1==>最后一位是1,其他位每位至少1个0
在n个数里选择k个作为AND和为1的目标子序列,其他的最后一位是0,前面任意
公式:C(k,n)×2^((m-1)(n-k))×(2^k-1)^(m-1)
代码片段:
int ar[maxn], top;
int mod;
int add(int a, int b) {
return ((a += b) >= mod) ? a - mod : a;
}
int mul(int x, int y) {
return (ll) x * y % mod;
}
int C[maxn];
void init(int n) {
for (int i = 1; i <= n; ++i) C[i] = 0;
C[0] = 1;
for (int i = 1; i <= n; ++i) {
for (int j = i; j; --j) {
C[j] = add(C[j], C[j - 1]);
}
}
}
int fpow(int a, int b) {
int ans = 1;
while (b) {
if (b & 1) ans = mul(ans, a);
a = mul(a, a);
b >>= 1;
}
return ans;
}
void solve() {
ll n, m;
cin >> n >> m >> mod;
if (mod == 1) {
cout << '0' << endl;
return;
}
init(n);
int ans = 0;
for (int i = 1; i <= n; ++i) {
int a = add(fpow(2, i), mod - 1);
a = fpow(a, m - 1);
int b = (m - 1) * (n - i) % (mod - 1);
b = fpow(2, b);
a = mul(a, b);
a = mul(a, C[i]);
ans = add(ans, a);
}
cout << ans << endl;
}
I - Mirror Maze
I-Mirror Maze_2024牛客暑期多校训练营1 (nowcoder.com)https://ac.nowcoder.com/acm/contest/81596/I
题目大意:
有一个n×m的矩形镜子迷宫,镜子有“\, /, -, |” 四种,有q个询问,每个询问给定一个点光源(x, y, dir),表示在(x, y) 位置向dir方向发射一束光线,问这束光线被多少个不同的镜子反射过。(1≤n, m≤1000, 1≤q≤1e5)
思路:
对于每一种状态(x,y,dir),无论之前是怎么过来的,经过他之后的路径就是一定的了
dfs,因为经过了之后后面有多少点就求过一次了,状态就是4mn
特殊:在同一个圈内的次数一致,在圈外的是后继节点+1(后继节点为反射前一次,与中途未经反射的镜子数无关)
代码片段:
int n, m, i, j, Q, tt;
int mp[1005][4], a[1005][1005], v[1005][1005][4], ans[1005][1005][4], fs[1005][1005];
int dx[4], dy[4];
string s;
string t;
vector<tuple<int, int, int, int>> q;
vector<pair<int, int>> vv;
void dfs(int x, int y, int d) {
if (x < 1 || y < 1 || x > n || y > m) {
ans[x][y][d] = 0;
return;
}
if (v[x][y][d]) {
tt = 1;
return;
}
int nxt = mp[a[x][y]][d];
v[x][y][d] = 1;
q.push_back({x, y, d, d != nxt});
x += dx[nxt];
y += dy[nxt];
dfs(x, y, nxt);
}
void trys(int x, int y, int d) {
tt = 0;
q = {};
vv = {};
if (x < 1 || y < 1 || x > n || y > m) {
ans[x][y][d] = 0;
return;
}
dfs(x, y, d);
reverse(q.begin(), q.end());
int sum = 0;
if (tt) {
for (auto [x,y,d,z]: q)
if (z && !fs[x][y]) {
fs[x][y] = 1;
sum++;
vv.push_back({x, y});
}
for (auto [x,y,d,z]: q) {
ans[x][y][d] = sum;
}
} else {
for (auto [x,y,d,z]: q) {
if (z && !fs[x][y]) {
fs[x][y] = 1;
sum++;
vv.push_back({x, y});
}
ans[x][y][d] = sum;
}
}
for (auto [i,j]: vv) fs[i][j] = 0;
}
void solve() {
int x, y, d;
memset(ans, -1, sizeof(ans));
dx[0] = -1;
dx[2] = 1;
dy[1] = 1;
dy[3] = -1;
mp['-'][0] = 2;
mp['-'][1] = 1;
mp['-'][2] = 0;
mp['-'][3] = 3;
mp['|'][0] = 0;
mp['|'][1] = 3;
mp['|'][2] = 2;
mp['|'][3] = 1;
mp['/'][0] = 1;
mp['/'][1] = 0;
mp['/'][2] = 3;
mp['/'][3] = 2;
mp['\\'][0] = 3;
mp['\\'][1] = 2;
mp['\\'][2] = 1;
mp['\\'][3] = 0;
cin >> n >> m;
for (i = 0; i < n; i++) {
cin >> s;
for (j = 0; j < m; j++) {
a[i + 1][j + 1] = s[j];
}
}
for (i = 1; i <= m; i++) {
trys(i, 1, 1);
trys(i, m, 3);
}
for (i = 1; i <= n; i++) {
trys(1, i, 2);
trys(n, i, 0);
}
cin >> Q;
while (Q--) {
cin >> x >> y >> t;
if (t == "above") {
d = 0;
}
if (t == "right") {
d = 1;
}
if (t == "below") {
d = 2;
}
if (t == "left") {
d = 3;
}
x += dx[d];
y += dy[d];
if (!v[x][y][d]) {
trys(x, y, d);
}
cout << ans[x][y][d] << endl;
}
}