目录
C:Delete Edges(构造,思维)
题意:
你有一张n(3≤n≤2000)个点的无向完全图,你需要删掉一些边,让这张图里面边数小于n,输出你删除边的方案。
思路:
这个图一共有 条边,我们必须要删除至少
条边。我们需要构造出尽可能多的三元组,还要保证任意两对三元组里相同的点不能超过1个.
官方给出的答案是的所有解。
那么我们只需要保证进行暴力即可。
(证明不会)
#include <bits/stdc++.h>
using namespace std;
struct node
{
int x, y, z;
};
int main()
{
int n;
cin >> n;
vector<node> v;
for (int i = 1; i <= n; i++)
{
for (int j = i + 1; j <= n; j++)
{
int k = (n - i - j + n) % n;
if (k == 0)
k = n;
if (j < k)
v.push_back({i, j, k});
}
}
cout << v.size() << endl;
for (auto i : v)
{
printf("%d %d %d\n",i.x,i.y,i.z);
}
}
F:Hamburger Steak(思维)
题意:
n块牛排,m个烤盘,每块牛排要烤分钟,而且最多可以分两次烤,只要时间达到
就行,输出最小花费时间时,每块牛排的烤制方案,按照时间顺序输出。
思路:
考虑一个时间上限
首先考虑每一块牛排,可以发现至少为
(牛排需要最长时间的那个)
从总体来看,我们还要保证成立
也就是
在这两种情况取一个max,就确定了这个时间上限。
接下来模拟每个锅的分配时间即可。
(注意一个坑点,要按照时间顺序输出)
#include <bits/stdc++.h>
#define int long long
using namespace std;
const int N = 1e5 + 10;
int t[N];
signed main()
{
int n, m;
cin >> n >> m;
int sum = 0;
int mx = 0;
for (int i = 1; i <= n; i++)
{
cin >> t[i];
sum += t[i];
mx = max(mx, t[i]);
}
int limt = (sum + m - 1) / m;
limt = max(mx, limt);
int id = 1, last = 0;
for (int i = 1; i <= n; i++)
{
if (last + t[i] <= limt)
{
cout << 1 << " " << id << " " << last << " " << last + t[i] << endl;
last += t[i];
}
else
{
t[i] -= (limt - last);
cout << 2;
cout << " " << id + 1 << " " << 0 << " " << t[i] << " ";
cout << " " << id << " " << last << " " << limt <<endl;
id++;
last = 0;
last += t[i];
}
if (last == limt)
id++, last = 0;
}
}
H:Hopping Rabbit(线段树维护扫描线)
题意:
二维平面,一些矩阵块不能进,兔子每次会上下左右选择一个方向,移动dd个单位。找一个起点,使得不管怎么走都不会走到非法矩阵块里。
思路:
考虑兔子不动,矩阵往兔子靠近。我们可以把这些矩阵全部缩进一个矩阵中表示所有情况,如果这个矩阵有没覆盖的格子,那么那个坐标就是一个合法的答案。
如何缩进一个矩阵
来自题解
比如这个我就可以缩成这样
把每个矩阵对d取模分情况讨论
变成一个(d-1)*(d-1)的矩阵后,我们要找到没有覆盖的点,用扫描线从下往上扫,如果扫到这一行有没有覆盖的点,我们暴力从左往右找就行。
不是很会扫描线,参考别人的代码,唉
#include <bits/stdc++.h>
// #define int long long
using namespace std;
const int N = 5e5 + 10;
struct scanline
{
int l, r, x;
};
vector<scanline> v[N];
struct node
{
int cnt, len; //覆盖多少次,cnt>0的区间总长度
} tre[N];
int n, d;
int ql,qr;
void add(int x1,int x2,int y1,int y2)
{
v[x1].push_back({y1,y2,1});
v[x2+1].push_back({y1,y2,-1});
}
void pushup(int rt,int l,int r)
{
if(tre[rt].cnt)
tre[rt].len=r-l+1;
else if(l==r)
tre[rt].len=0;
else
tre[rt].len=tre[rt<<1].len+tre[rt<<1|1].len;
}
void change(int rt,int l,int r,int x)
{
if(ql<=l&&r<=qr)
{
tre[rt].cnt+=x;
pushup(rt,l,r);
return ;
}
int mid=(l+r)>>1;
if(ql<=mid)
change(rt<<1,l,mid,x);
if(qr>mid)
change(rt<<1|1,mid+1,r,x);
pushup(rt,l,r);
}
int get(int rt,int l,int r)
{
if(tre[rt].len==0)
{
return l;
}
int mid=(l+r)>>1;
if(tre[rt<<1].len<mid-l+1)
return get(rt<<1,l,mid);
else
return get(rt<<1|1,mid+1,r);
}
signed main()
{
scanf("%d%d", &n, &d);
for (int i = 1; i <= n; i++)
{
int x1, y1, x2, y2;
scanf("%d%d%d%d", &x1, &y1, &x2, &y2);
--x2, --y2;
if (x2 - x1 + 1 >= d)
x1 = 0, x2 = d - 1;
if (y2 - y1 + 1 >= d)
y1 = 0, y2 = d - 1;
x1=(x1%d+d)%d;
x2=(x2%d+d)%d;
y1=(y1%d+d)%d;
y2=(y2%d+d)%d;
if(x1<=x2)
{
if(y1<=y2)
add(x1,x2,y1,y2);
else
add(x1,x2,0,y2),add(x1,x2,y1,d-1);
}
else
{
if(y1<=y2)
add(0,x2,y1,y2),add(x1,d-1,y1,y2);
else
add(0,x2,0,y2),add(x1,d-1,0,y2),add(0,x2,y1,d-1),add(x1,d-1,y1,d-1);
}
}
for(int i=0;i<d;i++)
{
for(int j=0;j<v[i].size();j++)
{
ql=v[i][j].l;
qr=v[i][j].r;//当前扫描线的左右端点
change(1,0,d-1,v[i][j].x);
}
if(tre[1].len<d)
{
printf("YES\n");
printf("%d %d",i,get(1,0,d-1));
return 0;
}
}
cout<<"NO";
}