第二场相对第一场还行,出的题感觉都不错。
A题:
做法:暴力遍历一下就行,代码如下:
/*
coder:sunshine
school:njupt
*/
#include <bits/stdc++.h>
using namespace std;
#define endl '\n' //交互题删掉
#define x first
#define y second
typedef long long ll;
typedef pair<int, int> PII;
const int mod = 1e9 + 7;
void solve()
{
int n, l, r, a, b;
cin >> n >> l >> r >> a >> b;
int ans = 0;
for (int i = l; i <= r; i++)
{
int j = n - i;
if (j >= a && j <= b)
ans++;
}
cout << ans << endl;
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(nullptr);
int t;
cin >> t;
while (t--)
{
solve();
}
return 0;
}
B题:
Tokitsukaze and a+b=n (medium)
做法:推公式 O ( 1 ) O(1) O(1)做就行,代码如下:
for _ in range(int(input())):
n=int(input())
l,r=map(int,input().split())
ll,rr=map(int,input().split())
print(max(0,min(n-l,rr)-max(n-r,ll)+1))
J题:
做法:根据数学推导,最终式子就是
a
n
s
=
2
n
∑
i
=
1
n
a
b
s
(
a
i
)
ans=2n\sum _{i=1}^n abs(a_i)
ans=2ni=1∑nabs(ai)
for _ in range(int(input())):
n=int(input())
l=[]
sum=0;
l=list(map(int,input().split()))
for a in l:
sum+=abs(a)
print(sum*n*2)
D题:
做法:是一道贪心加树的DFS,从下往上看,越下面的节点会被算法的越多,例如自己作为根节点会被算一次,父亲节点作为根节点会被算一次,爷爷节点作为根还会被算一次,以此类推,所以要越深的节点值越大,总价值就会更大,代码如下:
/*
coder:sunshine
school:njupt
*/
#include <bits/stdc++.h>
using namespace std;
#define endl '\n' //交互题删掉
#define x first
#define y second
typedef long long ll;
typedef pair<int, int> PII;
const int mod = 1e9 + 7;
const int N = 2e5 + 10;
int n, fa[N];
vector<int> g[N];
ll w[N], dep[N];
void dfs(int now, int d)
{
dep[now] = d;
for (auto to : g[now])
{
dfs(to, d + 1);
}
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(nullptr);
cin >> n;
for (int i = 2; i <= n; i++)
{
cin >> fa[i];
g[fa[i]].push_back(i);
}
for (int i = 1; i <= n; i++)
{
cin >> w[i];
}
dfs(1, 1);
sort(w + 1, w + n + 1);
sort(dep + 1, dep + n + 1);
ll ans = 0;
for (int i = 1; i <= n; i++)
{
ans += dep[i] * w[i];
}
cout << ans << endl;
return 0;
}
C题:
做法:这里两个区间要求不能是相同的区间,所以可以先算任意两个区间总的选法,再减去区间相同带来的方案数,就是最终答案。因为会区间修改,所以还需要用差分来维护,代码如下:
/*
coder:sunshine
school:njupt
*/
#include <bits/stdc++.h>
using namespace std;
#define endl '\n' //交互题删掉
#define x first
#define y second
typedef long long ll;
typedef pair<int, int> PII;
const ll mod = 998244353ll;
const int N = 2e5 + 10;
ll n, m;
ll f[N];
ll calc(ll l, ll r)
{
ll x0 = max(n - r, l);
ll x1 = min(n - l, r);
ll dx = max(0ll, x1 - x0 + 1);
return dx;
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(nullptr);
ll ans = 0;
cin >> n >> m;
while (m--)
{
int l, r;
cin >> l >> r;
f[l]++, f[r + 1]--;
ans = (ans - calc(l, r) + mod) % mod;
}
for (int i = 1; i < N; i++)
{
f[i] += f[i - 1];
}
for (int i = 1; i < N; i++)
{
int j = n - i;
if (j > N || j <= 0)
continue;
ll num = f[i] * f[j] % mod;
ans = (ans + num) % mod;
}
cout << ans << endl;
return 0;
}
H题:
做法:假设数字 x x x 出现的次数为 c n t x cnt_x cntx:
- 如果 c n t x ≤ k cnt_x≤k cntx≤k,我们可以贪心地将每个 x x x 都分到某个子序列中,使得每个子序列要么只包含 1 个 x x x,要么不包含 x x x。所以此时数字 x x x 的贡献为 c n t x cnt_x cntx
- 如果 c n t x > k cnt_x>k cntx>k,我们按照上面的方法分配完 k k k 个 x x x,多出来的 x x x 必须分配到某个子序列中,导致那个子序列中,数字 x x x 没有贡献。所以此时数字 x x x 的贡献为 k − 1 k−1 k−1
答案就是每种数字的贡献求和,代码如下:
/*
coder:sunshine
school:njupt
*/
#include <bits/stdc++.h>
using namespace std;
#define endl '\n' //交互题删掉
typedef long long ll;
typedef pair<int, int> PII;
const int mod = 1e9 + 7;
const int N = 1e5 + 10;
int a[N], c[N];
void solve()
{
memset(c, 0, sizeof c);
int n;
cin >> n;
multiset<int> st;
for (int i = 1; i <= n; i++)
{
cin >> a[i];
c[a[i]]++;
}
for (int i = 1; i <= 1e5; i++)
{
st.insert(c[i]);
}
ll lesum = 0, ge = ((int)st.size());
for (int i = 1; i <= n; i++)
{
while (!st.empty() && (*st.begin()) <= i)
{
lesum += (ll)(*st.begin());
st.erase(st.begin());
ge--;
}
cout << lesum + ge * (i - 1) << endl;
}
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(nullptr);
int t;
cin >> t;
while (t--)
{
solve();
}
return 0;
}
L题:
tokitsukaze and Three Integers
做法:还是注意到 i ! = j ! = k i!=j!=k i!=j!=k,可以先算出所有的答案,再减去有相等的时候的方案数,就是最终答案,这里 n n n较大,需要预处理,代码如下:
/*
coder:sunshine
school:njupt
*/
#include <bits/stdc++.h>
using namespace std;
#define endl '\n' //交互题删掉
#define x first
#define y second
typedef long long ll;
typedef pair<int, int> PII;
const int mod = 1e9 + 7;
const int N = 5010;
int a[N], c[N], d[N][N];
int main()
{
ios::sync_with_stdio(false);
cin.tie(nullptr);
int n, p;
cin >> n >> p;
for (int i = 1; i <= n; i++)
{
cin >> a[i];
a[i] %= p;
}
for (int i = 1; i <= n; i++)
{
for (int j = 1; j <= n; j++)
{
if (i == j)
continue;
c[a[i] * a[j] % p]++;
d[i][a[j] * a[i] % p] += 2;
}
}
for (int i = 0; i < p; i++)
{
ll ans = 0;
for (int k = 1; k <= n; k++)
{
ll tar = (i - a[k] + p) % p;
ans += (c[tar] - d[k][tar]);
}
cout << ans << " ";
}
cout << endl;
return 0;
}
F题:
Tokitsukaze and Gold Coins (easy)
做法:这个简单版本一开始没人做,其实直接暴力BFS就行,代码如下:
/*
coder:sunshine
school:njupt
*/
#include <bits/stdc++.h>
using namespace std;
#define endl 'n' //交互题删掉
typedef long long ll;
typedef pair<int, int> PII;
const int mod = 1e9 + 7;
const int N = 5e5 + 10;
int n, k;
bool can[N][3];
int f[N][3];
int g[N][3];
int main()
{
int t;
scanf("%d", &t);
while (t--)
{
scanf("%d%d", &n, &k);
for (int i = 1; i <= n; i++)
{
for (int j = 0; j < 3; j++)
{
can[i][j] = true;
f[i][j] = g[i][j] = false;
}
}
for (int i = 0, x, y; i < k; i++)
{
scanf("%d%d", &x, &y);
can[x][y - 1] = !can[x][y - 1];
}
queue<pair<int, int>> que;
f[1][0] = 1;
que.emplace(1, 0);
while (!que.empty())
{
auto [x, y] = que.front();
que.pop();
if (y < 2 && can[x][y + 1] && !f[x][y + 1])
{
f[x][y + 1] = 1;
que.emplace(x, y + 1);
}
if (x < n && can[x + 1][y] && !f[x + 1][y])
{
f[x + 1][y] = 1;
que.emplace(x + 1, y);
}
}
g[n][2] = 1;
que.emplace(n, 2);
while (!que.empty())
{
auto [x, y] = que.front();
que.pop();
if (y > 0 && can[x][y - 1] && !g[x][y - 1])
{
g[x][y - 1] = 1;
que.emplace(x, y - 1);
}
if (x > 0 && can[x - 1][y] && !g[x - 1][y])
{
g[x - 1][y] = 1;
que.emplace(x - 1, y);
}
}
int ans = 0;
for (int i = 1; i <= n; i++)
{
for (int j = 0; j < 3; j++)
{
if (f[i][j] && g[i][j] && !(i == 1 && j == 0))
{
ans++;
}
}
}
printf("%d\n", ans);
}
return 0;
}