test20230817考试总结(思维训练)
前言#
这一次思维训练,我感觉到了巨佬们的强大,也感受到了我与巨佬们的差距。
A | B | C | D | E | F |
---|---|---|---|---|---|
√ | √ | √ | ✖ | √ | √ |
A#
Problem#
给定一个长度为
现在有一种操作:将
求序列可能达到的状态数。
Solve#
显然,两个连续的
这样只要考虑”落单的”奇数个
对于一个落单的
红色的
但是这样就会变被很复杂。
换一种思路,不是
所以只要统计捆绑起来的
设两个连续的
Code#
#include <bits/stdc++.h>
#define int long long
#define H 19260817
#define rint register int
#define For(i,l,r) for(rint i=l;i<=r;++i)
#define FOR(i,r,l) for(rint i=r;i>=l;--i)
#define MOD 1000003
#define mod 998244353
using namespace std;
inline int read() {
rint x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if (ch=='-') f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
return x*f;
}
void print(int x){
if(x<0){putchar('-');x=-x;}
if(x>9){print(x/10);putchar(x%10+'0');}
else putchar(x+'0');
return;
}
const int N = 2e5 + 10;
int inv[N], fac[N], n;
char a[N];
int qpow(int a, int b) {
int res = 1;
while(b) {
if(b & 1) res = (res % mod * a % mod) % mod;
a = (a % mod * a % mod) % mod, b >>= 1;
}
return res;
}
int C(int m, int n) {
return fac[n] * inv[m] % mod * inv[n-m] % mod;
}
void solve() {
scanf("%d%s", &n, a + 1);
int num1 = 0, num2 = 0, i = 1;
for (; i <= n; i++) {
if(a[i] == '1' && a[i+1] == '1') num1++, i++;
else if(a[i] == '0') num2++;
}
cout << C(num1, num1 + num2) << '\n';
return ;
}
signed main() {
fac[0] = inv[0] = fac[1] = inv[1] = 1;
For(i,2,N-10) {
fac[i] = (fac[i-1] % mod * i % mod) % mod;
inv[i] = 1ll * (mod - mod / i) * inv[mod % i] % mod;
}
For(i,2,N-10) {
inv[i] = inv[i-1] * inv[i] % mod;
}
int Q = read();
while(Q--) {
solve();
}
return 0;
}
时间复杂度
B#
Problem#
给定一个
有两种事件:
- 奶牛
移动到了 或 点,则停止运动,并做 的体重贡献; - 当奶牛
和 奶牛 占据了相同点,则互换速度。奶牛可能在一个非整数点相遇;
令
Solve#
考虑将问题化简:两个奶牛相遇时,对穿并且互换体重。这样与原问题等价,但更好处理。
考虑一个奶牛
假设这个奶牛的为
计算出每一个奶牛到牛棚的距离,由于奶牛的运动方向恒定,所以对于每一个奶牛都有唯一的终点。然后对于每一个先到终点的奶牛,计算该奶牛的贡献。这里是
这样就可以计算出
总时间复杂度
Code#
#include <bits/stdc++.h>
#define ll long long
#define H 19260817
#define rint register int
#define For(i,l,r) for(rint i=l;i<=r;++i)
#define FOR(i,r,l) for(rint i=r;i>=l;--i)
#define MOD 1000003
#define mod 1000000007
#define getchar()(p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++)
char buf[1<<21],*p1=buf,*p2=buf;
using namespace std;
inline int read() {
rint x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if (ch=='-') f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
return x*f;
}
void print(int x){
if(x<0){putchar('-');x=-x;}
if(x>9){print(x/10);putchar(x%10+'0');}
else putchar(x+'0');
return;
}
const int N = 1e5 + 10;
struct Node {
int w, x, d;
} a[N];
struct node {
int id, x, d;
bool operator < (const node &a) const {
return a.x < x;
}
};
int n, l, now, s1[N], s2[N], laL, laR, Q[N], ans, sum, T;
priority_queue<node> q;
bool cmp(Node x, Node y) {
return x.x < y.x;
}
signed main() {
n = read(), l = read();
For(i,1,n) a[i] = (Node) {read(), read(), read()};
sort(a + 1, a + n + 1, cmp);
For(i,1,n) {
q.push((node){i, (a[i].d == 1 ? l - a[i].x : a[i].x), a[i].d});
s1[i] = s1[i-1] + (a[i].d == 1), s2[i] = s2[i-1] + (a[i].d == -1);
sum += a[i].w;
}
FOR(i,n,1) {
if(a[i].d == 1) laL = i;
}
For(i,1,n) {
if(a[i].d == -1) laR = i;
}
while(!q.empty()) {
int id = q.top().id, x = q.top().x, d = q.top().d;
q.pop();
int dis = (d == 1 ? s1[laR] - s1[id] : s2[id-1] - s2[laL-1]);
T = x;
if(d == 1) {
now += a[laR - dis].w;
} else {
now += a[laL + dis].w;
}
if(now * 2 >= sum) break;
}
int h = 1, t = 0;
For(i,1,n) {
if(a[i].d == 1) Q[++t] = i;
else {
while(h <= t && a[i].x - a[Q[h]].x > 2 * T) h++;
ans += t - h + 1;
}
}
cout << ans << '\n';
return 0;
}
C#
Problem#
有一个
Solve#
一眼换根
每一次我的操作肯定是想要树更胖,即根节点更有可能成为重心。
考虑求出这棵树改哪个子树上的边能使其更胖。
首先这棵子树一定要合法,并且它的大小要最大。
注意
然后考虑换根
当然还有一个细节,定义 以
Code#
#include <bits/stdc++.h>
#define int long long
#define H 19260817
#define rint register int
#define For(i,l,r) for(rint i=l;i<=r;++i)
#define FOR(i,r,l) for(rint i=r;i>=l;--i)
#define MOD 1000003
#define mod 1000000007
using namespace std;
inline int read() {
rint x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if (ch=='-') f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
return x*f;
}
void print(int x){
if(x<0){putchar('-');x=-x;}
if(x>9){print(x/10);putchar(x%10+'0');}
else putchar(x+'0');
return;
}
const int N = 1e6 + 10;
struct Node {
int v, nx;
} e[N << 1];
int n, h[N], tot, siz[N], Max[N][2], rt, cut[N], ans[N];
void add(int u, int v) {
e[++tot].v = v, e[tot].nx = h[u], h[u] = tot;
}
void dfs1(int x, int fa) {
siz[x] = 1;
bool f = 1;
for (int i = h[x]; i; i = e[i].nx) {
int y = e[i].v;
if(y == fa) continue;
dfs1(y, x);
siz[x] += siz[y];
if(siz[y] > n / 2) f = 0;
}
if(n - siz[x] > n / 2) f = 0;
if(f) rt = x;
}
void dfs2(int x, int fa) {
siz[x] = 1;
for (int i = h[x]; i; i = e[i].nx) {
int y = e[i].v;
if(y == fa) continue;
dfs2(y, x);
siz[x] += siz[y];
if(siz[y] > n / 2) continue;
if(siz[y] > Max[x][0]) Max[x][1] = Max[x][0], Max[x][0] = siz[y];
else if(siz[y] > Max[x][1]) Max[x][1] = siz[y];
}
}
void dfs3(int x, int fa, int maxn) {
cut[x] = maxn;
for (int i = h[x]; i; i = e[i].nx) {
int y = e[i].v;
if(y == fa) continue;
if(n - siz[x] <= n / 2) maxn = max(maxn, n - siz[x]);
if(Max[x][0] == siz[y]) dfs3(y, x, max(maxn, Max[x][1]));
else dfs3(y, x, max(maxn, Max[x][0]));
}
if(n - siz[x] - cut[x] <= n / 2 || x == rt) ans[x] = 1;
}
signed main() {
n = read();
For(i,1,n-1) {
int u = read(), v = read();
add(u, v); add(v, u);
}
dfs1(1, 0);
dfs2(rt, 0);
dfs3(rt, 0, 0);
For(i,1,n) cout << ans[i] << ' ';
return 0;
}
D#
Problem#
给定一张有向简单图,给定邻接矩阵,求长度为
Solve#
不会啊~
Code#
不会啊~
E#
Problem#
对于一个长度为
给你一个长度为
Solve#
可以证明,
证明:
所以
有了这一个结论,直接暴力将
记得开 long long。
Code#
#include <bits/stdc++.h>
#define int long long
#define H 19260817
#define rint register int
#define For(i,l,r) for(rint i=l;i<=r;++i)
#define FOR(i,r,l) for(rint i=r;i>=l;--i)
#define MOD 1000003
#define mod 1000000007
using namespace std;
inline int read() {
rint x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if (ch=='-') f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
return x*f;
}
void print(int x){
if(x<0){putchar('-');x=-x;}
if(x>9){print(x/10);putchar(x%10+'0');}
else putchar(x+'0');
return;
}
const int N = 5e3 + 10;
int n, x[N], f[N], num[N], ans[N];
int find(int x) {
return (x == f[x] ? x : f[x] = find(f[x]));
}
void merge(int x, int y) {
f[find(x)] = find(y);
}
signed main() {
n = read();
For(i,1,n) x[i] = read(), f[i] = i;
For(i,1,n) {
For(j,i+1,n) {
if(x[i] * x[j] > 0) {
int tmp = sqrt(x[i] * x[j]);
if(tmp * tmp == x[i] * x[j]) {
merge(i, j);
}
}
}
}
int tot = 0;
For(i,1,n) {
tot = 0;
memset(num, 0, sizeof num);
For(j,i,n) {
if(!x[j]) ans[max(1ll, tot)]++;
else {
if(!num[find(j)]) {
num[find(j)] = 1; tot++;
}
ans[tot]++;
}
}
}
For(i,1,n) cout << ans[i] << ' ';
return 0;
}
F#
Problem#
给定一个正整数序列
; ;
答案对
Solve#
显然,在决策第
设
递推式为:
答案为
发现
但是时空双炸,然后就推进不下去了。
换一种思路,考虑容斥,称满足
发现对于长度为
设
则有:
这里的
转移时间复杂度为
找到从
因为
由于
这些操作可以通过单调栈来实现。
边界:
Code#
#include <bits/stdc++.h>
#define int long long
#define H 19260817
#define rint register int
#define For(i,l,r) for(rint i=l;i<=r;++i)
#define FOR(i,r,l) for(rint i=r;i>=l;--i)
#define MOD 1000003
#define mod 998244353
using namespace std;
inline int read() {
rint x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if (ch=='-') f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
return x*f;
}
void print(int x){
if(x<0){putchar('-');x=-x;}
if(x>9){print(x/10);putchar(x%10+'0');}
else putchar(x+'0');
return;
}
const int N = 2e5 + 10;
int n, a[N], stk[N], f[N][2], s[N][2], top;
signed main() {
n = read();
For(i,1,n) a[i] = read();
f[0][0] = s[0][0] = 1;
For(i,1,n) {
while(top && a[stk[top]] >= a[i]) top--;
f[i][0] = ((top == 0 ? 0 : f[stk[top]][0]) % mod + (s[i-1][1] - (top == 0 ? 0 : s[stk[top]-1][1]) + mod) * a[i]) % mod;
f[i][1] = ((top == 0 ? 0 : f[stk[top]][1]) % mod + (s[i-1][0] - (top == 0 ? 0 : s[stk[top]-1][0]) + mod) * a[i]) % mod;
s[i][0] = (s[i-1][0] + f[i][0]) % mod;
s[i][1] = (s[i-1][1] + f[i][1]) % mod;
stk[++top] = i;
}
cout << ((n & 1 ? mod - 1 : 1) * (f[n][0] - f[n][1] + mod) % mod) % mod;
return 0;
}
作者:Daniel-yao
出处:https://www.cnblogs.com/Daniel-yao/p/17640335.html
版权:本作品采用「署名-非商业性使用-相同方式共享 4.0 国际」许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】