2022.9.24———【CSP-S模拟10】游寄
\(Preface\)
\(Rank42/42\) 垫底了我超
\(0pts + 12pts + 0pts + 0pts = 12pts\)
T1 欧几里得的噩梦,T2 清扫,T3 购物,T4 ants
\(\mathfrak{T1}\ 欧几里得的噩梦\)
上来就干了一个线性基,我没学。
他说的全集就是本来所有的能异或出来的所有数,那么可能会有一些数在里面是可以被替代的,我们就是要把这些数扔出去,使得剩下的数能够异或出来的数和全集相同。
对于每个数给出的 \(x\text{,}y\),先判断一下 \(x\) 和 \(y\) 是否是属于同一个联通块的,如果是那么就说明他们两个合成的数已经出现过了,无需将此数加入子集,因为他加进去后并没有贡献。
然后再用并查集将 \(x\) 和 \(y\) 连起来继续跑就行了。
T1
#include <iostream>
#define GMY (520&1314)
#define FBI_OPENTHEDOOR(x) freopen(#x ".in", "r", stdin), freopen(#x ".out", "w", stdout);
#define int long long
#define re register int
#define char_phi signed
#define DMARK cerr << "###"
#define _ ' '
#define Endl cout << '\n'
#define Dendl cerr << '\n'
#define MIN(x, y) (((x) < (y)) ? (x) : (y))
#define MAX(x, y) (((x) > (y)) ? (x) : (y))
#define N 500005
#define P 1000000007
#define mod %
using namespace std;
inline void Fastio_setup(){ios::sync_with_stdio(false); cin.tie(NULL), cout.tie(NULL);}
int n, m;
int fa[N], ans[N];
int find(int x){return ((fa[x] == x) ? (x) : (fa[x] = find(fa[x])));}
inline int ksm(int A, int B){
int res(1);
while (B != 0){
if ((B & 1) == 1) res = res * A mod P;
A = A * A mod P;
B >>= 1;
}
return res;
}
inline void work(){
cin >> n >> m;
for (re i = 1 ; i <= m ; ++ i)
fa[i] = i;
fa[m+1] = m+1;
for (re i = 1, opt, x, y ; i <= n ; ++ i){
cin >> opt;
if (opt == 1)
{cin >> x; y = m+1;}
else
cin >> x >> y;
x = find(x), y = find(y);
fa[x] = y;
if (x != y)
ans[++ ans[0]] = i;
}
cout << ksm(2, ans[0]) << _ << ans[0] << '\n';
for (re i = 1 ; i <= ans[0] ; ++ i)
cout << ans[i] << _;
Endl;
}
// #define IXINGMY
char_phi main(){
#ifdef IXINGMY
FBI_OPENTHEDOOR(a);
#endif
Fastio_setup();
work();
return GMY;
}
\(\mathfrak{T2}\ 清扫\)
再次解释题意
你能一直扫,并不是你每个叶子组合只能扫一次。
但是我赛时并不这么认为,我就认为你每个叶子组合只能扫一次。听CD讲题的时候一脸蒙。哪来的方程???
但就这还能水到 \(12pts\) 真的震惊(
正解不会,贺题解
建议去看 \(\text{kiritokazuto}\) 的博客dsu
T2
#include <iostream>
#define GMY (520&1314)
#define FBI_OPENTHEDOOR(x) freopen(#x ".in", "r", stdin), freopen(#x ".out", "w", stdout);
#define int long long
#define re register int
#define char_phi signed
#define DMARK cerr << "###"
#define _ ' '
#define Endl cout << '\n'
#define Dendl cerr << '\n'
#define MIN(x, y) (((x) < (y)) ? (x) : (y))
#define MAX(x, y) (((x) > (y)) ? (x) : (y))
#define N 100005
using namespace std;
inline void Fastio_setup(){ios::sync_with_stdio(false); cin.tie(NULL), cout.tie(NULL);}
struct star{int v, nxt;};
int n, star_cnt, rt, Du1;
char isl[N];
int head[N], a[N], sz[N], son[N];
struct star e[N<<1];
inline void star_add(int u, int v){e[++ star_cnt].v=v, e[star_cnt].nxt=head[u], head[u]=star_cnt;}
void GetLeaf(int x, int faer){
char isleaf(true);
for (re i = head[x] ; i ; i = e[i].nxt){
int v = e[i].v;
if (v == faer)
continue;
isleaf = false;
GetLeaf(v, x);
}
if (isleaf == true)
isl[x] = true;
}
char dfs(int x, int faer){
if (isl[x] == true)
{sz[x] = a[x]; return true;}
for (re i = head[x] ; i ; i = e[i].nxt){
int v = e[i].v;
if (v == faer)
continue;
if (dfs(v, x) == false)
return false;
sz[x] += sz[v];
if (son[x] == 0 or sz[v] > sz[son[x]])
son[x] = v;// 重儿子
}
if (sz[x] < a[x])
return false;
int mx = (sz[son[x]]<<1) - sz[x];
sz[x] = (a[x]<<1) - sz[x];
return ((sz[x] >= 0) and (sz[x] >= mx));
}
inline void work(){
cin >> n;
for (re i = 1 ; i <= n ; ++ i)
cin >> a[i];
for (re i = 1, uu, vv ; i <= n-1 ; ++ i)
{cin >> uu >> vv; star_add(uu, vv), star_add(vv, uu); Du1 += ((uu == 1) or (vv == 1));}
char ok;
if (n == 2)
goto Special;
rt = ((Du1 == 1) ? (e[head[1]].v) : (1));
GetLeaf(rt, 0);
ok = dfs(rt, 0);
cout << (((ok == true) and (sz[rt] == 0)) ? ("YES") : ("NO")) << '\n';
return ;
Special:{
cout << ((a[1] == a[2]) ? ("YES") : ("NO")) << endl;
}
}
// #define IXINGMY
char_phi main(){
#ifdef IXINGMY
FBI_OPENTHEDOOR(a);
#endif
Fastio_setup();
work();
return GMY;
}
\(\mathfrak{T3}\ 购物\)
一个水结论题。
直接打表出规律,发现这玩意与前缀和、\(a_i\) 很有关系,然后直接大胆猜测结论就行了。
结论:如果 \(a_i > sum_{i-1}\),那么就会在 \(sum_{i-1} \sim \frac{a_i - 1}{2}\) 的位置出现空缺。
先初始化答案为 \(sum_n\),然后依次找到空缺并将其减去就行了。
这个结论是有证明的,由 \(\text{SMTwy}\) 给出,但是他现在还没写我去催催他,催成了的话我就把链接挂这里。
总结:
\[
觉得是规律题的题一定要『排序』还有『大量打表』!
\]
T3
#include <iostream>
#include <algorithm>
#include <cmath>
#define GMY (520&1314)
#define FBI_OPENTHEDOOR(x) freopen(#x ".in", "r", stdin), freopen(#x ".out", "w", stdout);
#define re register int
#define char_phi signed
#define DMARK cerr << "###"
#define _ ' '
#define Endl cout << '\n'
#define Dendl cerr << '\n'
#define MIN(x, y) (((x) < (y)) ? (x) : (y))
#define MAX(x, y) (((x) > (y)) ? (x) : (y))
#define N 100005
using namespace std;
inline void Fastio_setup(){ios::sync_with_stdio(false); cin.tie(NULL), cout.tie(NULL);}
/*
一个水结论题。
*/
long long n, final_ans;
long long a[N], sum[N];
inline void work(){
cin >> n;
for (re i = 1 ; i <= n ; ++ i)
cin >> a[i];
sort(a+1, a+n+1);
for (re i = 1 ; i <= n ; ++ i)
sum[i] = sum[i-1]+a[i];
final_ans = sum[n];
for (re i = 1 ; i <= n ; ++ i){
if (a[i]/2 > sum[i-1])
final_ans -= ((a[i]-1)/2 - sum[i-1]);
}
cout << final_ans << '\n';
}
// #define IXINGMY
char_phi main(){
#ifdef IXINGMY
FBI_OPENTHEDOOR(a);
#endif
Fastio_setup();
work();
return GMY;
}
\(\mathfrak{T4}\ ants\)
我的建议是
这题是原题
就是permu
只不过数据加强了一点
回滚莫队板子
T4
#include <iostream>
#include <algorithm>
#include <cmath>
#include <cstring>
#define GMY (520&1314)
#define FBI_OPENTHEDOOR(x) freopen(#x ".in", "r", stdin), freopen(#x ".out", "w", stdout);
#define int long long
#define re register int
#define char_phi signed
#define DMARK cerr << "###"
#define _ ' '
#define Endl cout << '\n'
#define Dl cerr << '\n'
#define MIN(x, y) (((x) < (y)) ? (x) : (y))
#define MAX(x, y) (((x) > (y)) ? (x) : (y))
#define N 100005
using namespace std;
inline void Fastio_setup(){ios::sync_with_stdio(false); cin.tie(NULL), cout.tie(NULL);}
int n, Q, top, blocklen;
int a[N], L[N], R[N], ans[N], belong[N];
struct Stack{int pos, w;};
struct Question{
int l, r, id;
friend bool operator < (Question A, Question B){
if (belong[A.l] != belong[B.l])
return A.l < B.l;
else
return A.r < B.r;// 超 排序锅了
}
};
struct Question q[N];
struct Stack s[N];
inline void work(){
cin >> n >> Q; blocklen = sqrt(n);
for (re i = 1 ; i <= n ; ++ i)
{cin >> a[i]; belong[i] = (i-1)/blocklen + 1;}
for (re i = 1 ; i <= Q ; ++ i)
{cin >> q[i].l >> q[i].r; q[i].id = i;}
/*cerr.tie(NULL);
cerr << n << _ << Q << '\n';
for (re i = 1 ; i <= n ; ++ i)
cerr << a[i] << '\n';
for (re i = 1 ; i <= Q ; ++ i)
cerr << q[i].l << _ << q[i].r << '\n';*/
sort(q+1, q+Q+1);
/*for (re i = 1 ; i <= Q ; ++ i)
cerr << belong[q[i].l] << _;
Dl;*/
int l(1), r(0), res(0);
int* it = NULL;
for (re i = 1 ; i <= Q ; ++ i){
if (belong[q[i].l] != belong[q[i-1].l]){
memset(L, 0, sizeof(L)), memset(R, 0, sizeof(R));
l = r = belong[q[i].l]*blocklen; res = 0;
}
while (r < q[i].r){
r ++;
L[a[r]] = L[a[r]-1]+1, R[a[r]] = R[a[r]+1]+1;
int len = L[a[r]]+R[a[r]]-1, lp = a[r]-L[a[r]]+1, rp = a[r]+R[a[r]]-1;
L[rp] = R[lp] = len;
res = MAX(res, len);
}
int ano(res);
top = 0;
for (re j = q[i].l ; j <= MIN(q[i].r, l) ; ++ j){
L[a[j]] = L[a[j]-1] + 1, R[a[j]] = R[a[j]+1] + 1;
int len = L[a[j]]+R[a[j]]-1, lp = a[j]-L[a[j]]+1, rp = a[j]+R[a[j]]-1;
s[++ top] = (Stack){rp, L[rp]}, s[++ top] = (Stack){lp, R[lp]};
L[rp] = R[lp] = len; ano = MAX(ano, len);
}
for (re j = top ; j >= 1 ; -- j){
if ((j & 1) == 1)
it = &L[s[j].pos];
else
it = &R[s[j].pos];
*it = s[j].w;
}
for (re j = q[i].l ; j <= MIN(q[i].r, l) ; ++ j)
L[a[j]] = R[a[j]] = 0;
ans[q[i].id] = ano;
}
for (re i = 1 ; i <= Q ; ++ i)
cout << ans[i] << '\n';
Endl;
}
// #define IXINGMY
char_phi main(){
#ifdef IXINGMY
FBI_OPENTHEDOOR(a);
#endif
Fastio_setup();
work();
return GMY;
}
$$\huge{\mathcal{Here\ We\ Are,\ Nick\ Of\ Time\ !}}$$