Week4 题解
洛谷题解
A
不知道为什么题目挂了, 直接求前缀和板子题, 这题甚至不用开 ll
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
using ull = unsigned long long;
using pii = pair<int, int>;
constexpr int inf = 0x3f3f3f3f;
void solve(){
int n;
cin >> n;
vector<int> a(n + 1);
for(int i=1; i<=n; i++){
cin >> a[i];
}
vector<int> pre(n + 1);
for(int i=1; i<=n; i++){
pre[i] = pre[i-1] + a[i];
}
for(int i=1; i<=n; i++){
cout << pre[i] << " \n"[i == n];
}
}
int main(){
ios::sync_with_stdio(false);
cin.tie(nullptr);
int t = 1; //cin >> t;
while(t--) solve();
return 0;
}
B
求个差分就行
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
using ull = unsigned long long;
using pii = pair<int, int>;
constexpr int inf = 0x3f3f3f3f;
void solve(){
int n;
cin >> n;
vector<int> a(n + 1);
for(int i=1; i<=n; i++){
cin >> a[i];
}
vector<int> diff(n + 1);
for(int i=1; i<=n; i++){
diff[i] = a[i] - a[i-1];
}
for(int i=1; i<=n; i++){
cout << diff[i] << " \n"[i == n];
}
}
int main(){
ios::sync_with_stdio(false);
cin.tie(nullptr);
int t = 1; //cin >> t;
while(t--) solve();
return 0;
}
C
区间快速加应用
时间复杂度 O(q + n)
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
using ull = unsigned long long;
using pii = pair<int, int>;
constexpr int inf = 0x3f3f3f3f;
void solve(){
int n, q;
cin >> n >> q;
vector<int> a(n + 2);
for(int i=1; i<=n; i++){
cin >> a[i];
}
vector<ll> diff(n + 2);
for(int i=1; i<=n; i++){
diff[i] = a[i] - a[i-1];
}
for(int i=0; i<q; i++){
int x, y, v;
cin >> x >> y >> v;
diff[x] += v;
diff[y+1] -= v;
}
for(int i=1; i<=n; i++){
a[i] = a[i-1] + diff[i];
}
cout << *min_element(a.begin()+1, a.begin()+1+n) << '\n';
// for(int i=1; i<=n; i++){
// cout << a[i] << " \n"[i == n];
// }
}
int main(){
ios::sync_with_stdio(false);
cin.tie(nullptr);
int t = 1; //cin >> t;
while(t--) solve();
return 0;
}
D
可以二值化, G为1, R为-1
当选取的字串 cntG 等于 cntR 时则稳定, 也就是区间和为 0 时
区间和为零也就是 preL == preR , 代表 [L+1, R] 的区间是稳定的
GGRRG
1 2 1 0 1
因此 , 我们用 map 记录前缀和数组中每种值的最早出现的位置
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
using ull = unsigned long long;
using pii = pair<int, int>;
constexpr int inf = 0x3f3f3f3f;
void solve(){
string s;
cin >> s;
int n = s.size();
s = " " + s;
vector<ll> pre(n + 1);
for(int i=1; i<=n; i++){
pre[i] = (s[i]=='G'? 1:-1);
}
for(int i=1; i<=n; i++){
pre[i] += pre[i-1];
}
map<ll, int> mp;
mp[0] = 0; // 初始化 0 的情况
int ans = 0;
for(int i=1; i<=n; i++){
if(mp.count(pre[i])) ans = max(ans, i-mp[pre[i]]);
else mp[pre[i]] = i;
}
cout << ans << '\n';
}
int main(){
ios::sync_with_stdio(false);
cin.tie(nullptr);
int t = 1; //cin >> t;
while(t--) solve();
return 0;
}
E
n <= 120, 直接 O(n^4) 暴力遍历所有矩阵, 用前缀和优化求和
#include <bits/stdc++.h>
using namespace std;
void solve(){
int n;
cin >> n;
vector<vector<int>> a(n + 1, vector<int>(n + 1));
vector<vector<int>> pre(n + 1, vector<int>(n + 1));
for(int r = 1; r <= n; r++){
for(int c = 1; c <= n; c++){
cin >> a[r][c];
}
}
for(int r = 1; r <= n; r++){
for(int c = 1; c <= n; c++){
pre[r][c] = pre[r-1][c] + pre[r][c-1] - pre[r-1][c-1] + a[r][c];
}
}
int ans = 0;
for(int r1=1; r1<=n; r1++){
for(int r2=r1; r2<=n; r2++){
for(int c1=1; c1<=n; c1++){
for(int c2=c1; c2<=n; c2++){
int s = pre[r2][c2]
- pre[r1-1][c2]
- pre[r2][c1-1]
+ pre[r1-1][c1-1];
ans = max(ans, s);
}
}
}
}
cout << ans << '\n';
}
int main(){
ios::sync_with_stdio(false);
cin.tie(nullptr);
solve();
return 0;
}
F
注意 x, y 可能等于 0 , 并且一个点可能有多个目标
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
void solve(){
int n, m;
cin >> n >> m;
vector<vector<int>> mat(5000 + 2, vector<int>(5000 + 2, 0));
vector<vector<int>> pre(5000 + 2, vector<int>(5000 + 2, 0));
for(int i = 0; i < n; i++){
int x, y, v;
cin >> x >> y >> v;
mat[x + 1][y + 1] += v; // 平移坐标轴
}
for(int r = 1; r <= 5000 + 1; r++){
for(int c = 1; c <= 5000 + 1; c++){
pre[r][c] = mat[r][c] + pre[r-1][c] + pre[r][c-1] - pre[r-1][c-1];
}
}
int ans = 0;
for(int r = 1; r + m - 1 <= 5000 + 1; r++){
for(int c = 1; c + m - 1 <= 5000 + 1; c++){
int x1 = r, y1 = c;
int x2 = r + m - 1, y2 = c + m - 1;
int s = pre[x2][y2] - pre[x1 - 1][y2] - pre[x2][y1 - 1] + pre[x1 - 1][y1 - 1];
ans = max(ans, s);
}
}
cout << ans << '\n';
}
int main(){
ios::sync_with_stdio(false);
cin.tie(nullptr);
solve();
return 0;
}
G
二位前缀和板题 , 矩形区域加
#include <bits/stdc++.h>
using namespace std;
void solve(){
int n, m;
cin >> n >> m;
vector<vector<int>> diff(n + 2, vector<int>(n + 2, 0));
for(int i = 0; i < m; i++){
int x1, y1, x2, y2;
cin >> x1 >> y1 >> x2 >> y2;
diff[x1][y1] += 1;
diff[x1][y2 + 1] -= 1;
diff[x2 + 1][y1] -= 1;
diff[x2 + 1][y2 + 1] += 1;
}
vector<vector<int>> ans(n + 1, vector<int>(n + 1, 0));
for(int r = 1; r <= n; r++){
for(int c = 1; c <= n; c++){
ans[r][c] = diff[r][c] + ans[r-1][c] + ans[r][c-1] - ans[r-1][c-1];
}
}
for(int r = 1; r <= n; r++){
for(int c = 1; c <= n; c++){
cout << ans[r][c] << " ";
}
cout << '\n';
}
}
int main(){
ios::sync_with_stdio(false);
cin.tie(nullptr);
solve();
return 0;
}
H
只有两个方向 , 先选定一个方向 , 然后枚举向前走多远后折返走相反方向
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
constexpr int inf = 0x3f3f3f3f;
void solve(){
int n, m;
cin >> n >> m;
const int MX = 1e6;
int ext = 0;
vector<int> L(MX + 1), R = L;
for(int i=0; i<n; i++){
int x; cin >> x;
if(x < 0) L[-x]++;
if(x == 0) ext++;
if(x > 0) R[x]++;
}
for(int i=1; i<=MX; i++){
L[i] += L[i-1];
R[i] += R[i-1];
}
int ans = 0;
for(int i=0; i<=MX; i++){
int rest = m - 2*i;
if(rest < 0) break;
rest = min(rest, MX);
ans = max(ans, L[i]+R[rest]+ext);
}
for(int i=0; i<=MX; i++){
int rest = m - 2*i;
if(rest < 0) break;
rest = min(rest, MX);
ans = max(ans, L[rest]+R[i]+ext);
}
cout << ans << '\n';
}
int main(){
ios::sync_with_stdio(false);
cin.tie(nullptr);
int t = 1; //cin >> t;
while(t--) solve();
return 0;
}
G
博弈, 可以发现, 无论怎么取, 在取完之前无法停止, 所以数一下石子总数即可
总数量奇数 Alice 赢
总数量偶数 Bob 赢
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
void solve(){
int n;
cin >> n;
ll sum = 0;
for(int i=0; i<n; i++){
int x; cin >> x;
sum += x;
}
cout << (sum&1? "Alice":"Bob") << '\n';
}
int main(){
ios::sync_with_stdio(false);
cin.tie(nullptr);
solve();
return 0;
}
周赛题解
7-1
因为是被 10 整除, 可以直接放在 %10 的意义下来看
当 pre[L] == pre[R] 时 , 也就是 sum[L+1, R] 的和为 0 (mod 10 意义下)
然后和作业题 D 就几乎是一道题了
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
constexpr int inf = 0x3f3f3f3f;
void solve(){
int n;
cin >> n;
vector<int> a(n + 1);
for(int i=1; i<=n; i++){
cin >> a[i];
}
vector<ll> pre(n + 1);
for(int i=1; i<=n; i++){
pre[i] = pre[i-1] + a[i];
}
vector<int> fir(10, inf);
fir[0] = 0;
int ans = 0;
for(int i=1; i<=n; i++){
ans = max(ans, i-(fir[pre[i]%10]));
fir[pre[i]%10] = min(fir[pre[i]%10], i);
}
cout << ans << '\n';
}
int main(){
ios::sync_with_stdio(false);
cin.tie(nullptr);
int t = 1; //cin >> t;
while(t--) solve();
return 0;
}
7-2
区间加简单题
#include<bits/stdc++.h>
using namespace std;
#define int long long
const int N = 1e6+5;
const int mod=998244353;
int a[N];
void run(){
int n,m;
cin>>n>>m;
for(int i=1;i<=m;i++){
int x,y,z;
cin>>x>>y>>z;
a[x]+=z;
a[y+1]-=z;
}
for(int i=1;i<=n;i++){
a[i]+=a[i-1];
}
for(int i=1;i<=n;i++){
cout<<a[i]<<' ';
}
}
signed main(){
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
int T=1;
// cin>>T;
while(T--)run();
return 0;
}
7-3
区间加简单题
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
constexpr int inf = 0x3f3f3f3f;
void solve(){
int n, k;
cin >> n >> k;
vector<int> a(n + 2);
for(int i=1; i<=k; i++){
int x, y;
cin >> x >> y;
a[x]++, a[y+1]--;
}
for(int i=1; i<=n; i++){
a[i] += a[i-1];
}
sort(a.begin()+1, a.begin()+1+n);
cout << a[(n+1)/2] << '\n';
}
int main(){
ios::sync_with_stdio(false);
cin.tie(nullptr);
int t = 1; //cin >> t;
while(t--) solve();
return 0;
}
7-4
需要先转化一下, 因为一天大概不到 1e5s, 开个数组然后用差分快速区间加即可
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
constexpr int inf = 0x3f3f3f3f;
void solve(){
int MX = 1e5;
vector<int> d(MX + 2);
int n; cin >> n;
for(int i=0; i<n; i++){
int h1, m1, s1;
int h2, m2, s2;
scanf("%d:%d:%d", &h1, &m1, &s1);
scanf("%d:%d:%d", &h2, &m2, &s2);
int x = h1*3600 + m1*60 + s1;
int y = h2*3600 + m2*60 + s2;
d[x]++, d[y+1]--;
}
int ans = 0;
for(int i=1; i<=MX; i++){
d[i] += d[i-1];
ans = max(ans, d[i]);
}
cout << ans << '\n';
}
int main(){
int t = 1; //cin >> t;
while(t--) solve();
}
7-5
按题意模拟判断一下即可
#include <bits/stdc++.h>
using namespace std;
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
int T, S, t;
if (!(cin >> T >> S >> t)) return 0;
if (T >= 35 && t >= 33 && S == 1) {
cout << "Bu Tie" << '\n' << T << '\n';
} else if (T >= 35 && t >= 33 && S == 0) {
cout << "Shi Nei" << '\n' << T << '\n';
} else if (S == 1) {
cout << "Bu Re" << '\n' << t << '\n';
} else {
cout << "Shu Shi" << '\n' << t << '\n';
}
return 0;
}
7-6
用双端队列存, 然后开个标记
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
constexpr int inf = 0x3f3f3f3f;
void solve(){
int q; cin >> q;
deque<int> dq;
bool ori = true;
for(int i=0; i<q; i++){
int op; cin >> op;
if(op == 1){
int x; cin >> x;
if(ori) dq.push_back(x);
else dq.push_front(x);
}
if(op == 2 && !dq.empty()){
if(ori) dq.pop_front();
else dq.pop_back();
}
if(op == 3) ori ^= 1;
if(dq.empty()) cout << -1 << '\n';
else cout << (dq.front()^dq.back()) << '\n';
}
}
int main(){
ios::sync_with_stdio(false);
cin.tie(nullptr);
int t = 1; //cin >> t;
while(t--) solve();
return 0;
}
7-7
贪心, 其实是求字典序最大, 我们将数字转化成字典序后按照 a+b > b+a 的顺序 sort 即可
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
constexpr int inf = 0x3f3f3f3f;
void solve(){
int n;
while(cin >> n){
vector<string> a(n);
for(int i=0; i<n; i++){
int x; cin >> x;
a[i] = to_string(x);
}
sort(a.begin(), a.end(), [](string x, string y){
return x+y > y+x;
});
for(auto x : a) cout << x;
cout << '\n';
}
}
int main(){
ios::sync_with_stdio(false);
cin.tie(nullptr);
int t = 1; //cin >> t;
while(t--) solve();
return 0;
}
7-8
从 x 到 y , 相当于 [x, y] 的次数都加了 1, 最后能得到每条路都经过了几次 , 在两种选择中取最优即可
#include<bits/stdc++.h>
#define int long long
#define itn int
#define endl '\n'
#define pii pair<int,int>
using namespace std;
const int MAX=1e6+7;
const int mod=1e9+7;
int p[MAX],a[MAX],b[MAX],c[MAX];
int sum[MAX];
void run(){
int n,m;cin >>n>>m;
for(int i=1;i<=m;i++){
cin >>p[i];
}
for(int i=1;i<n;i++){
cin >>a[i]>>b[i]>>c[i];
}
p[0]=1;
for(int i=2;i<=m;i++){
int mx=max(p[i],p[i-1]),mn=min(p[i],p[i-1]);
sum[mn]++,sum[mx]--;
}
for(int i=1;i<n;i++){
sum[i]+=sum[i-1];
}
int ans=0;
for(int i=1;i<n;i++){
// cout <<sum[i]<<' ';
ans+=min(a[i]*sum[i],b[i]*sum[i]+c[i]);
}
cout <<ans<<endl;
}
/*
*/
signed main(){
ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
int t=1;
// cin >>t;
for(int i=0;i<t;i++) run();
return 0;
}
7-9
需要动态的维护 sum 和 k 个值, 注意取模
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
constexpr int inf = 0x3f3f3f3f;
constexpr int mo = 1e9;
void solve(){
int n, k;
cin >> n >> k;
deque<int> dq(k, 1);
int sum = k;
for(int i=k; i<=n; i++){
dq.push_back(sum);
sum *= 2;
sum -= dq.front();
sum = (sum % mo + mo) % mo; // 防负
dq.pop_front();
}
cout << dq.back() << '\n';
}
int main(){
ios::sync_with_stdio(false);
cin.tie(nullptr);
int t = 1; //cin >> t;
while(t--) solve();
return 0;
}
7-10
整理一下式子, 其实就是 A1 * sum[2, n] + A2 * sum[3, n]...
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
constexpr int inf = 0x3f3f3f3f;
void solve(){
int n;
cin >> n;
vector<int> a(n + 1);
ll sum = 0;
for(int i=1; i<=n; i++){
cin >> a[i];
sum += a[i];
}
ll ans = 0;
for(int i=1; i<=n; i++){
sum -= a[i];
ans += a[i] * sum;
}
cout << ans << '\n';
}
int main(){
ios::sync_with_stdio(false);
cin.tie(nullptr);
int t = 1; //cin >> t;
while(t--) solve();
return 0;
}
7-11
这个题要从差分数组来看 , 每次操作等价于在差分数组选两个点一加一减, 或一减一加, 或单点±, 最后要求差分数组全为 0 (除了 d[1])
从差分数组来看就容易不少, 在上述操作下, 最小操作次数为 max(pos, neg)
\({pos = \sum_{i=2,di>0}^{n}d_i}\)
\({neg = \sum_{i=2,di<0}^{n}|d_i|}\)
因为当 pos, neg 都非 0 时, 我们最优肯定是进行一次操作操作让 pos--, neg--
当有一个为 0, 我们就只能让剩下的 --,
操作次数也就是 |pos-neg| + min(pos, neg) = max(pos, neg)
最后剩下的也就是 d[1]
d[1] 在第二步有一个为 0 时可以顺带进行操作
可能的种类数就是 |pos-neg| + 1
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
constexpr int inf = 0x3f3f3f3f;
void solve(){
int n;
cin >> n;
vector<int> a(n + 1);
for(int i=1; i<=n; i++){
cin >> a[i];
}
vector<int> d(n + 1);
d[1] = a[1];
int pos = 0, neg = 0;
for(int i=2; i<=n; i++){
d[i] = a[i] - a[i-1];
if(d[i] > 0) pos += d[i];
if(d[i] < 0) neg -= d[i];
}
cout << max(pos, neg) << '\n';
cout << abs(pos-neg) + 1 << '\n';
}
int main(){
ios::sync_with_stdio(false);
cin.tie(nullptr);
int t = 1; //cin >> t;
while(t--) solve();
return 0;
}
7-12
作业原题 , 参考作业 F 题 , 请在洛谷上提交

浙公网安备 33010602011771号