CSP-S 模拟7
CSP-S模拟7
为什么4、5、6都没写呢,真难猜啊。
简单地说,4:10pts(菜完了),5:12pts(挂288分),6:80pts(太菜导致的)。所以没心情写。
T1 花菖蒲
判断是否存在⼀棵树,满⾜它有 a 个⼀度点和 b 个三度点,如果存在请给出⼀个节点数不超过2000 的构造,否则输出 0。
有很多种写法,这里介绍 skk dashe 讲述的有机化学写法。
考虑将 \(三度点\) 看做碳(其实是氮吧!!!),将 \(一度点\) 看做氢,容易想到拉一条碳骨架往上面挂氢元素,中间的只能挂一个,两头的可以挂两个。如果碳有多余的就很可惜了,而氢如果有多余的话,可以考虑换掉其中一个氢,换成一个不是碳的元素(如果只能是碳就特判无解),然后往这个特别的元素上面挂氢(兴许是一个2000价的元素),将这一过程写出来就过了。
但是话说回来了,我没写出来,我直接模拟,分类讨论做出了 \(a \le b*2\) 的情况,只拿下 40......
倒是也好,就当是从唐走出来的第一步算了。那这算什么,半糖吗。
code:40pts模拟
200行,别看
#include <bits/extc++.h>
//#define submit
#ifdef submit
#define getchar getchar_unlocked
#define putchar putchar_unlocked
#endif
#define e_ putchar(' ')
#define en_ putchar('\n')
using namespace std;
using lint = long long;
template <typename T> inline T in(T &n) {
n = 0; char p = getchar();
while(p < '-') p = getchar();
// bool f = p == '-' ? p = getchar() : 0;
do n = (n << 1) + (n << 3) + (p ^ 48), p = getchar();
while(isdigit(p));
// return n = f ? -n : n;
return n;
}
template <typename T> inline void out(T x) {
// if(x < 0) putchar('-'), x = -x;
if (x >= 10) out(x / 10);
putchar(x % 10 + '0');
}
constexpr int N = 200000 + 10; const char me[] = "Ciallo";
int cnt[2010];
int sum[2010];
int fa[2010];
int find(int x) {return x == fa[x] ? fa[x] : fa[x] == find(fa[x]);}
queue<int> q[2010];
vector<int> e[2010];
inline void link(int a, int b) {
sum[cnt[a]]--, sum[cnt[b]]--;
e[a].push_back(b);
e[b].push_back(a);
cnt[a]++, cnt[b]++;
sum[cnt[a]]++, sum[cnt[b]]++;
fa[find(a)] = find(b);
}
inline void split(int a, int b) {
sum[cnt[a]]--, sum[cnt[b]]--;
for(unsigned int i = 0; i < e[a].size(); i++) {
if(e[a][i] == b) {
e[a].erase(e[a].begin() + i);
break;
}
}
for(unsigned int i = 0; i < e[b].size(); i++) {
if(e[b][i] == a) {
e[b].erase(e[b].begin() + i);
break;
}
}
e[b].push_back(a);
cnt[a]--, cnt[b]--;
sum[cnt[a]]++, sum[cnt[b]]++;
}
int sz[2010], ff[2010], vis[2010];
inline void dfs(int u) {
sz[u] = 1;
for(int v : e[u]) {
if(v != ff[u] and !vis[v]) {
ff[v] = u;
vis[v] = 1;
dfs(v);
sz[u] += sz[v];
}
}
}
inline bool ner1(int u) {
for(int v : e[u]) {
if(v == 1) return 1;
}
return 0;
}
inline int fi(int u, int fa) {
for(int v : e[u]) {
if(ner1(v)) {
return v;
}
}
for(int v : e[u]) {
if(v == fa) continue;
if(fi(v, u)) {
return fi(v, u);
}
}
return 0;
}
inline int fr(int x) {
queue<int>qw;
bitset<1000>vis;
qw.push(x);
while(!qw.empty()) {
int u = qw.front(); qw.pop();
if(vis[u] == 1) continue;
vis[u] = 1;
if(e[u].size() == 1) {
return u;
}
for(int v : e[u]) {
if(v != 1 and !vis[v])
qw.push(v);
}
}
return 0;
}
int main() {
freopen("irises.in", "r", stdin);
freopen("irises.out", "w", stdout);
int a, b;
in(a), in(b);
if(a == 0 and b == 0) {
out(1);
return 0;
}
if(a == 3 and b == 1) {
out(4), en_;
out(1), e_, out(4), en_;
out(2), e_; out(4), en_,
out(3), e_, out(4);
return 0;
}
if(a == 0) {
out(0);
return 0;
}
// zuiduo
if(b == 0) {
if(a == 1) {
cout << 0;
return 0;
}
if(a == 2) {
cout << "2\n1 2";
return 0;
}
if(a == 3) {
cout << 0;
return 0;
}
if(a >= 4) {
cout << a + 1 << '\n';
for(int i = 1; i <= a; i ++) {
out(i), e_, out(a + 1); en_;
}
return 0;
}
}
fa[1] = 1;
for(int i = 2; i <= 2000; i ++) {
q[0].push(i); fa[i] = i;
}
for(int i = 1; i <= b; i ++) {
int a1 = q[0].front(); q[0].pop();
int a2 = q[0].front(); q[0].pop();
int a3 = q[0].front(); q[0].pop();
int a4 = q[0].front(); q[0].pop();
link(a1, a2);
link(a1, a3);
link(a1, a4);
link(1, a2);
q[cnt[a2]].push(a2); q[cnt[3]].push(a3), q[cnt[a4]].push(a4);
q[cnt[a1]].push(a1);
}
int n = b * 2;
if(n <= a) {
if(a - n == 2) {
if(cnt[1] != 1) {
for(int i = 1; i <= 2; i ++) {
int a1 = q[0].front(); q[0].pop();
link(a1, 1);
q[cnt[a1]].push(a1);
}
}
if(cnt[1] == 1) {
cout << 0; return 0;
}
}
if(a - n == 1) {
if(cnt[1] != 2) {
int a1 = q[0].front(); q[0].pop();
int a2 = q[0].front(); q[0].pop();
link(a1, a2);
link(a1, 1);
q[cnt[a1]].push(a1), q[cnt[a2]].push(a2);
}
else {
cout << 0;
return 0;
}
}
if(a - n == 0) {
if(b == 1) {
cout << 0 ;
return 0;
}
if(b == 3) {
cout << 0;
return 0;
}
}
else {
int t = a - n;
// t > 2
for(int i = 1; i <= t; i ++) {
int a = q[0].front(); q[0].pop();
link(1, a);
}
}
}
else {
int pr = e[1][0], ccc = 0, yer = 0;
for(unsigned int i = 2; i < e[1].size(); i ++) {
int u = fi(e[1][i], 0);
split(u, 1);
pr = fr(pr);
link(pr, u);
if(u == 0) break;
ccc ++;
if(ccc == n - a) {
yer = 1;
break;
}
}
if(yer == 0) {
cout << 0; return 0;
}
}
ff[1] = 1;
dfs(1);
cout << sz[1] << '\n';
for(int i = 2; i <= 2000; i ++) {
if(ff[i]) {
out(i), e_, out(ff[i]), en_;
}
}
}
不妨看看正解罢。。。
#include <bits/extc++.h>
//#define submit
#ifdef submit
#define getchar getchar_unlocked
#define putchar putchar_unlocked
#endif //本来写了快读后来删了
#define e_ putchar(' ')
#define en_ putchar('\n')
using namespace std;
using lint = long long;
constexpr int N = 200000 + 10;
int a, b, n;
int main() {
freopen("irises.in", "r", stdin),
freopen("irises.out", "w", stdout);
ios::sync_with_stdio(0);
cin >> a >> b;
if(a == 3 && b == 1) {
cout << 4 << '\n';
cout << 1 << ' ' << 2 << '\n';
cout << 1 << ' ' << 3 << '\n';
cout << 1 << ' ' << 4 << '\n';
exit(0);
}
if(a == 2 && b == 0) {
cout << 2 << '\n'; // 这是甲烷
cout << 1 << ' ' << 2 <<'\n';
exit(0);
}
if(a == 0 && b == 0) {
cout << 1; // 这是氢气
exit(0);
}
if(a - b - 2 > 0) {
if(a - b - 2 == 1) { // 这几个特判都是粘的,不知道会不会被发现的说
cout << 0;
exit(0);
}
if(b == 0) {
if(a == 3) {
cout << 0;
exit(0);
}
cout << a + 1 << '\n';
for(int i = 2; i <= a + 1; i++)
cout << 1 << ' ' << i << '\n';
exit(0);
}
if(b == 1) {
n = a + b + 1;
cout << n << '\n';
cout << 1 << ' ' << 2 << '\n';
cout << 1 << ' ' << 3 << '\n';
cout << 1 << ' ' << 4 << '\n';
for(int i = 1; i <= a - 2; i++)
cout << 4 << ' ' << i + 4 << '\n';
exit(0);
}
n = a + b + 1;
cout << n << '\n';
for(int i = 1; i < b; i ++)
cout << i << ' ' << i + 1 << '\n';// 拉一个碳骨架
int tot = b + 1;
for(int i = 1; i <= b; i ++) {
if(i == 1 || i == b) {
cout << i << ' ' << tot << '\n';
cout << i << ' ' << tot + 1 << '\n';
tot += 2; //往上面挂氢(头尾)
}
else {
cout << i << ' ' << tot << '\n';
tot++; // 中间的
}
}
for(int i = 1; i <= a - b - 1; i++)
cout << tot - 1 << ' ' << tot - 1 + i << '\n';// 剩下的挂在一个诡秘元素上面
}
else if(a - b - 2 == 0) {
n = a + b;
cout << n << '\n';
for(int i = 1; i < b; i ++)
cout << i << ' ' << i + 1 << '\n';
int tot = b + 1;
for(int i = 1; i <= b; i ++) {
if(i == 1 || i == b) {
cout << i << ' ' << tot << '\n';
cout << i << ' ' << tot + 1 << '\n';
tot += 2;
}
else {
cout << i << ' ' << tot << '\n';
tot++;
}
}
}
else {
cout << 0;
}
}
T2 百日草
有⼀张 n 个点 m 条边的有向图,每条边上有⼀个正整数边权,你要顺着图上的有向边从 1 号点⾛到 n 号点。 假设你经过的边边权依次为 w[1], w[2]…w[t],则你的疲惫程度为 max{i * w[i]}(i <= t)。你需要找到最⼩疲惫程度的路径。
好像也有很多写法,不过我自己过了就说我自己写的罢。
私写法和官解同样,高兴呢。
本来想 dp 发现 "时间" 或者 "位置" 这两维很难同时设计,考虑弄掉一个。
注意到当上界一定的时候,一个点能不能转移和它原来的 ‘最短路’ 就没有关系了,可以只记录能够到达的点们,也就弄掉了空间这一维。再次注意到答案有单调性,可以二分答案,如下。
code:
点击查看代码
#include <bits/extc++.h>
//#define submit
#ifdef submit
#define getchar getchar_unlocked
#define putchar putchar_unlocked
#endif
#define e_ putchar(' ')
#define en_ putchar('\n')
using namespace std;
#define int long long
template <typename T> inline T in(T &n) {
n = 0; char p = getchar();
while(p < '-') p = getchar();
// bool f = p == '-' ? p = getchar() : 0;
do n = (n << 1) + (n << 3) + (p ^ 48), p = getchar();
while(isdigit(p));
// return n = f ? -n : n;
return n;
}
template <typename T> inline void out(T x) {
// if(x < 0) putchar('-'), x = -x;
if (x >= 10) out(x / 10);
putchar(x % 10 + '0');
}
constexpr int N = 300000 + 10; const char me[] = "Ciallo";
using node = pair<int, int>;
int n, m, w[N];
bool vis[N];
vector<node> e[N];
vector<int> vec[2]; // 不能给每一个时间都开一个,会爆空间(吗,我也没试过)
inline bool check(int lim) {
vec[1].clear();
vec[0].clear();
memset(vis, 0, sizeof vis);
int now = 1;
vis[1] = 1;
vec[now ^ 1].push_back(1);
for(int i = 1; i < n; i ++) { // i 是时间
now ^= 1;// 轮换一下
vec[now ^ 1].clear();
for(int u : vec[now]) {
for(node v : e[u]) {
if(!vis[v.first])
if(v.second * i <= lim) {
vis[v.first] = 1;
vec[now ^ 1].push_back(v.first);
}
}
}
if(vis[n]) return 1;
}
return vis[n];
}
signed main() {
freopen("zinnia.in", "r", stdin);
freopen("zinnia.out", "w", stdout);
// freopen("ex_b5.in", "r", stdin);
// 妈的比他妈T1好做一万倍 // 场上的暴戾语言
in(n); in(m);
for(int i = 1, u, v, w; i <= m; i ++) {
in(u), in(v), in(w);
e[u].push_back({v, w});
}
int l = 0, r = 1e17;
while (l < r) {
int mid = (l + r) >> 1;
if(check(mid)) r = mid;
else l = mid + 1;
}
cout << r;
}
T3 and T4
都不会,爆零,暴力都假了......(其实是文件名写错了)
展示题面
T3 紫丁香
给你⼀个 n 个点 m 条边的简单⽆向连通图,点从0 ∼ n − 1 编号,现在你需要删掉若⼲条边,最⼤化度数为奇数的点的个数。 当然了,你还需要给出构造,即输出⼀个⻓度为 m 的 01 串,1表⽰保留这个边,0表⽰删掉这个边,请输出字典序最⼤的⽅案。
T4 麒麟草
有⼀个r × c 的平⾯。 有 n 个矩形在平⾯上和 q 个查询。 每个查询给你⼀个矩形,询问这个矩形与给定的n个矩形相交的⾯积之并的⾯积。也可以认为是这n个矩形并的整个图形与给定矩形的交的⾯积。 矩形的给出⽅式为四个参数 x 1, y1, x 2, y 2,其中(x 1, y1), (x 2, y 2) 表⽰矩形不相邻的两个顶点。 注意有可能x 1 > x 2, y 1 > y2 或者 x 1 = x 2, y1 = y2,后者会退化成⼀条线,⾯积会变成 0。 本题强制在线
这题是可持久化扫描线,不会......

浙公网安备 33010602011771号