Educational Codeforces Round 171 (Rated for Div. 2)
A. Perpendicular Segments
分析
题目中的要求
而又要求线段垂直, 那么两线段可以放在一个正方形内做对角线
那么此时
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int,int>PII;
const int N=1e6+10;
const int mod=998244353;
const int INF = 0x3f3f3f3f;
const ll INFll = 0x3f3f3f3f3f3f3f3f;
#define endl "\n"
//vector<vector<int>>adj(N);
void solve()
{
int x, y, k;
cin >> x >> y >> k;
if(x > y) swap(x, y);
cout << "0 0 " << x << " " << x << endl;
cout << "0 " << x << " " << x << " 0" << endl;
}
signed main()
{
ios::sync_with_stdio(false);
cin.tie(0),cout.tie(0);
cout << setprecision(11) << fixed;
int t;t=1;
cin>>t;
for(int i=1;i<=t;i++){
//printf("Case %d: ",i);
solve();
}
}
B. Black Cells
赛时脑瘫了,看到
分析
直接二分
分析
如果
否则可以选一个不染,当发现此时
#include<bits/stdc++.h>
#define int long long
using namespace std;
typedef long long ll;
typedef pair<int,int>PII;
const int N=1e6+10;
const int mod=998244353;
const int INF = 0x3f3f3f3f;
const ll INFll = 0x3f3f3f3f3f3f3f3f;
#define endl "\n"
//vector<vector<int>>adj(N);
int a[N];
int b[N],c[N];
int n;
bool check(int mid) {
for(int i = 1; i + 1 <= n; i += 2) {
if(a[i + 1] - a[i] > mid) {
if(n % 2 == 0) return false;
if(i % 2 == 0) return false;
i --;
}
}
return true;
}
void solve()
{
cin >> n;
for(int i = 1; i <= n; i ++) {
cin >> a[i];
}
int l = 1, r = 1e18;
while(l < r) {
int mid = l + r >> 1;
if(check(mid)) r = mid;
else l = mid + 1;
}
cout << l << endl;
}
signed main()
{
ios::sync_with_stdio(false);
cin.tie(0),cout.tie(0);
cout << setprecision(11) << fixed;
int t;t=1;
cin>>t;
for(int i=1;i<=t;i++){
//printf("Case %d: ",i);
solve();
}
}
C. Action Figures
分析
首先,在某天买东西时,一定会试图免费第
所以,当
所以我们考虑那些物品可以被免费
逆向枚举每一天,同时,用一个队列来存需要免费的物品
- 如果
, 丢到队列里面 - 如果
, 记录价值,同时取出队首(最贵的)
当枚举后,队列可能不空,需要支付里面较小的一半的钱,同时也可以免费较大的
#include<bits/stdc++.h>
#define int long long
using namespace std;
typedef long long ll;
typedef pair<int,int>PII;
const int N=1e6+10;
const int mod=998244353;
const int INF = 0x3f3f3f3f;
const ll INFll = 0x3f3f3f3f3f3f3f3f;
#define endl "\n"
//vector<vector<int>>adj(N);
void solve()
{
int n; cin >> n;
string s; cin >> s;
s = " " + s;
int cnt = 0;
queue<int> q;
int ans = 0;
vector<int>a(n + 1);
for(int i = n; i >= 1; i --) {
if(s[i] == '1') q.push(i);
else {
ans += i;
if(q.size())q.pop();
}
}
int t = (q.size() + 1)/2; // 这里没明白可以改为双端队列,一个一个慢慢算
while(q.size()) {
if(q.size() <= t) ans += q.front();
q.pop();
}
cout << ans << endl;
}
signed main()
{
ios::sync_with_stdio(false);
cin.tie(0),cout.tie(0);
cout << setprecision(11) << fixed;
int t;t=1;
cin>>t;
for(int i=1;i<=t;i++){
//printf("Case %d: ",i);
solve();
}
}
D. Sums of Segments
写的最屎的一题,正在试图看懂赛时代码
分析
将题目的
举个例子,对于
- 前
行所有元素的和 - 第
行 的和
第一步,计算
- 这个挺好算的,计算
矩阵每一个元素的个数,做前缀和然后二分一下在多少行,减去前面的总数,就知道在当前行的第几个,参考代码中 数组的使用
第二步, 计算部分1
- 参考代码
数组
第三步, 计算部分2
- 对于第
行 的和,观察 矩阵, ; - 赛时写到这里想掏线段树了,但好在不带修。计算这个区间在第一行的和,对于第
行的每个元素,都多算了一次是 ,剪掉就好
把需要的东西都预处理好了,可以
参考代码一起看
#include<bits/stdc++.h>
#define int long long
using namespace std;
typedef long long ll;
typedef pair<int,int>PII;
const int N=1e6+10;
const int mod=998244353;
const int INF = 0x3f3f3f3f;
const ll INFll = 0x3f3f3f3f3f3f3f3f;
#define endl "\n"
//vector<vector<int>>adj(N);
void solve()
{
int n; cin >> n;
vector<int> a(n + 1, 0);
vector<int> s(n + 1, 0);
vector<int> b(n + 1, 0); // b数组的前n个元素,
vector<int> s2(n + 1, 0); // c矩阵中每一行的和
vector<int> s22(n + 1, 0);// s2的前缀和,用于快速计算c矩阵前i行的的和
vector<int> d(n + 1, 0); // c矩阵的每一行有效元素数量的前缀和,用来确定当前数在多少行
for(int i = 1; i <= n; i ++) {
cin >> a[i];
s[i] = a[i] + s[i - 1];
b[i] = b[i - 1] + s[i];
d[i] = n - i + 1 + d[i - 1];
}
s22[1] = s2[1] = b[n];
for(int i = 2; i <= n; i ++) {
s2[i] = s2[i - 1] - (n - i + 2) * a[i - 1];
s22[i] = s2[i] + s22[i - 1];
}
auto get = [&](int l, int r) -> int { // 计算c矩阵中,从(l,l)到(l, l + r - 1)的和
return b[r] - b[l - 1] - (s[l - 1]) * (r - l + 1);
};
auto calc = [&](int x) -> int {
int i = lower_bound(d.begin() + 1, d.end(), x) - d.begin();
int res = s22[i - 1];
x -= d[i - 1];
res += get(i, i + x - 1);
return res;
};
int q; cin >> q;
while(q --) {
int x, y; cin >> x >> y;
cout << calc(y) - calc(x - 1) << endl;
}
}
signed main()
{
ios::sync_with_stdio(false);
cin.tie(0),cout.tie(0);
cout << setprecision(11) << fixed;
int t;t=1;
//cin>>t;
for(int i=1;i<=t;i++){
//printf("Case %d: ",i);
solve();
}
}
E. Best Subsequence
听说是最小权闭合子图,但赛时写到这只有十几分钟了,而且根本没看出来是网络流
分析
很板子的一个题目,最难的地方就是看出他是板子
如果选择了
可以参考我代码里面的注释
hack时间还没结束,满猜有人每次memset(h, -1, sizeof h)会被卡
#include<bits/stdc++.h>
#define int long long
using namespace std;
typedef long long ll;
typedef pair<int,int>PII;
const int N=200+10,M = 2 * N * N;
const int mod=998244353;
const int INF = 0x3f3f3f3f3f3f3f3f;
const ll INFll = 0x3f3f3f3f3f3f3f3f;
#define endl "\n"
/*
使用说明
需要识别出闭合子图,
所谓闭合子图就是给定一个有向图,从中选择一些点组成一个点集V。对于V中任意一个点,其后续节点都仍然在V中
闭合子图(选择出点集,没有出去的有向边)
选择一个闭合子图, 这个权是最大的
举例
制造一些物品,可以获得对应的利益,
同时在制作的过程中,需要花费一些代价去买需要的东西
那么物品到对应的所需物品就有一个边,如果我选择了这个物品,那就一定要选择所需物品,
这不仅仅是题目的要求,也是我选出的点集构成闭合子图的关键
注意点
1.所需物品应该是不会被消耗的,如果可以被消耗,那么直接将所需花费从获利中剪掉就行
(?)如果物品有消耗次数,制作某个物品只会被消耗一部分,没碰见过,不知道
2.所需物品是多个制作品可以共用的,(可以 != 必须)
只服务单次制作的话,直接剪掉就好,理由同上
做法
转化为最小割,用最大流求解
1.原本所有的依赖关系全部保留,但是容量是INF
2.所有的制作获利, 将他们从S连边,容量是 本次获利
3.所有的依赖品 , 全部连向T, 容量是 abs(消耗)
从源点s向每个正权点连一条容量为权值的边,每个负权点向汇点t连一条容量为权值的绝对值的边,有向图原来的边容量全部为无限大。
跑完后,ans = sum(正权) - 最小割
最优性
最小割=(不选的正权之和+要选的负权绝对值之和)
最大权闭合子图=(正权之和-不选的正权之和-要选的负权绝对值之和)=正权值和-最小割
因为正权值和,是定值,而最小割保证值最小,所以最大权闭合子图一定最优。
详细解释链接
https://blog.csdn.net/can919/article/details/77603353
*/
//vector<vector<int>>edg(N);
int n, m, S, T;
ll h[N], e[M], ne[M], f[M], idx;
int d[N], cur[N];
void add(int a, int b, int c) {
// cout << a << " " << b << " " << c << endl;
e[idx] = b, f[idx] = c, ne[idx] = h[a], h[a] = idx ++;
e[idx] = a, f[idx] = 0, ne[idx] = h[b], h[b] = idx ++;
}
bool bfs() {
memset(d, -1, sizeof d);
queue<int> q;
q.push(S), d[S] = 0, cur[S] = h[S];
while(q.size()) {
int u = q.front(); q.pop();
for(int i = h[u]; ~i; i = ne[i]) {
int v = e[i];
if(d[v] == -1 && f[i]) {
d[v] = d[u] + 1;
cur[v] = h[v];
if(v == T) return true;
q.push(v);
}
}
}
return false;
}
int find(int u, ll limit) {
if(u == T) return limit;
ll flow = 0;
for(int i = cur[u]; ~i && flow < limit; i = ne[i]) {
int v = e[i];
cur[u] = i;
if(d[v] == d[u] + 1 && f[i]) {
int t = find(v, min(f[i], limit - flow));
if(!t) cur[u] = -1;
f[i] -= t, f[i ^ 1] += t, flow += t;
}
}
return flow;
}
ll dinic() {
ll ans = 0, flow;
while(bfs())
if(flow = find(S, INF))
ans += flow;
return ans;
}
int id64[100], aid[N], id;
int a[N];
void clear() {
memset(h, -1, sizeof h);
id = 0;
idx = 0;
}
void solve()
{
int n;
cin >> n;
S = id++, T = id++;
for(int i = 0; i < 63; i ++) {
id64[i] = id++;
add(id64[i], T, 1);
}
for(int i = 1; i <= n; i ++) {
cin >> a[i];
aid[i] = id ++;
for(int j = 0; j < 63; j ++) {
if((a[i] >> j) & 1) add(aid[i], id64[j], INF);
}
add(S, aid[i], 1);
}
cout << n - dinic() << endl;
}
signed main()
{
ios::sync_with_stdio(false);
cin.tie(0),cout.tie(0);
cout << setprecision(11) << fixed;
int t;t=1;
cin>>t;
for(int i=1;i<=t;i++){
clear();
//printf("Case %d: ",i);
solve();
}
}
分类:
codeforce
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧