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 题 , 请在洛谷上提交

posted @ 2025-11-18 23:28  EcSilvia  阅读(0)  评论(0)    收藏  举报