×

AIGC标识 20261007做题记录

上午类模拟赛

T1:

简单模拟。

点击查看代码
#include<bits/stdc++.h>
using namespace std;
#define N 200005
#define intl long long
#define For(i,a,b) for(intl i=a;i<=b;i++)
#define deo(i,a,b) for(intl i=a;i>=b;i--)
intl read() {
	intl x=0,k=1;char ch=getchar();
	while(!isdigit(ch)) {if(ch == '-') k=-1;ch=getchar();}
	while(isdigit(ch)) {x=(x<<3)+(x<<1)+(ch^48);ch=getchar();}
	return x*k;
}
intl n, h, l, r, ans;
int main() {
	freopen("weight.in","r",stdin);
	freopen("weight.out","w",stdout);
	n = read(), h = read(), r = h;
	For(i,1,n-1) {
		intl b = read(), nl = max(0ll,b-r), nr = min(h,b-l);
		if(nl > nr) ans++, l = 0, r = h;
		else l = nl, r = nr;
	}
	printf("%lld\n",ans);
	return 0;
}

T2:

我们发现可以分情况讨论。

  1. \(a_i > a_{i+1}\):
    显然,答案不会变小,那么显然我们只需要预处理出 \(i+1\) 后面的第一个数比 \(a_i\) 大的最长上升子序列和 \(i\) 前面最后一个数比 \(a_{i+1}\) 小的最长上升子序列就可以了,答案为原来的和把找到的这两个子序列拼起来的长度+2最大值。
  2. \(a_i < a_{i+1}\)
    显然,答案不会变大,我们发现答案什么时候变小,我们发现就是在原来长度的所有LIS都会经过 \(i\) 和 \(i+1\),这该怎么做,其实就是如果某一条 LIS 经过 \(i\) 那么有 \(f_i + g_i - 1 = len\) 其中,\(f_i\) 表示以 \(i\) 结尾的 LIS 长度,\(g_i\) 表示以 \(i\) 开头的 LIS 长度,\(len\) 为全局的 LIS 长度, 那么如果 \(cnt_{f_i} = 1\) 那么就代表所有 LIS 到会经过 \(i\),其中 \(cnt_{f_i}\) 表示所有 LIS 上的点以自己为结尾的LIS的长度为 \(f_i\) 数量,那么显然,如果数量为 \(1\) 则代表所有 LIS 都要经过自己,对 \(i\) 和 \(i+1\) 判断一下就可以了,答案为如果必经过就是原 \(LIS-1\) 否则就是 LIS。
点击查看代码
#include<bits/stdc++.h>
using namespace std;
#define N 200005
#define intl long long
#define For(i,a,b) for(int i=a;i<=b;i++)
#define deo(i,a,b) for(int i=a;i>=b;i--)
intl read() {
	intl x=0,k=1;char ch=getchar();
	while(!isdigit(ch)) {if(ch == '-') k=-1;ch=getchar();}
	while(isdigit(ch)) {x=(x<<3)+(x<<1)+(ch^48);ch=getchar();}
	return x*k;
}
intl n, a[N], f[N], g[N], pre[N], suf[N], cnt[N], len;
struct BIT{
	intl tr[N];
	void add(intl x,intl v) {
		for(;x<=n;x+=x&-x) tr[x] = max(tr[x],v);
	}
	intl ask(intl x) {
		intl ans = 0;
		for(;x;x-=x&-x) ans = max(ans,tr[x]);
		return ans;
	}
}bit; 
bool check(intl x) {
	return f[x]+g[x]-1 == len && cnt[f[x]] == 1;
}
int main() {
	freopen("lis.in","r",stdin);
	freopen("lis.out","w",stdout);
	n = read();
	For(i,1,n) a[i] = read();
	For(i,1,n) {
		if(i < n) pre[i] = bit.ask(a[i+1]-1);
		f[i] = bit.ask(a[i]-1)+1;
		bit.add(a[i],f[i]);
		len = max(len,f[i]);
	}
	memset(bit.tr,0,sizeof bit.tr);
	deo(i,n,1) {
		if(i > 1) suf[i-1] = bit.ask(n-a[i-1]);
		g[i] = bit.ask(n-a[i])+1;
		bit.add(n-a[i]+1,g[i]);
	}
	For(i,1,n) if(f[i]+g[i]-1 == len) cnt[f[i]]++;
	For(i,1,n-1) {
		intl ans = len;
		if(a[i] > a[i+1]) ans = max(ans,pre[i]+2ll+suf[i]);
		else if(check(i) && check(i+1)) ans--;
		printf("%lld ",ans);
	}
	return 0;
}

T3:

不会。

T4:

不会。

CF1385E

简单题,显然,我们可以先对有向边做拓扑排序,然后对于无向边我们将其定向为拓扑序标号小的指向大的就可以了,无解当且仅当原有向边构成环。

证明

显然,按照拓扑序之后,就可以发现我们可能存在拓扑序编号小的指向大的,但是一定不存在编号大的指向小的路径,那么如果我们像这样给无向边定向之后,就一定不存在环。

点击查看代码
#include<bits/stdc++.h>
using namespace std;
#define N 200005
#define intl long long
#define For(i,a,b) for(intl i=a;i<=b;i++)
#define deo(i,a,b) for(intl i=a;i>=b;i--)
intl read() {
	intl x=0,k=1;char ch=getchar();
	while(!isdigit(ch)) {if(ch == '-') k=-1;ch=getchar();}
	while(isdigit(ch)) {x=(x<<3)+(x<<1)+(ch^48);ch=getchar();}
	return x*k;
}
intl n, m, id[N], deg[N];
vector<intl> g[N];
void solve() {
	n = read(), m = read();
	vector<pair<intl,intl>> vec, ans;
	For(i,1,m) {
		intl t = read(), u = read(), v = read();
		if(t) ans.push_back({u, v}), g[u].push_back(v), deg[v] ++;
		else vec.push_back({u, v});
	}
	intl idx = 0;
	queue<intl> q;
	For(i,1,n) if(!deg[i]) q.push(i);
	while(q.size()) {
		auto u = q.front();q.pop();
		id[u] = ++idx;
		for(auto v:g[u]) if(!--deg[v]) q.push(v);
	}
	if(idx != n) return puts("No"), void();
	for(auto [u, v]:vec) {
		if(id[u] < id[v]) ans.push_back({u, v});
		else ans.push_back({v, u});
	}
	puts("Yes");
	for(auto [u,v]:ans) printf("%lld %lld\n", u, v);
}
void clear() {
	For(i,1,n) id[i] = deg[i] = 0, g[i].clear();
}
int main() {
	intl T = read();
	while(T --) solve(), clear();
	return 0;
}


CF977E

简单题,问我们每个联通块是不是一个环,我们就只需要检查每个联通块里面是不是每个点的度数都等于2就可以了。

点击查看代码
#include<bits/stdc++.h>
using namespace std;
#define N 200005
#define intl long long
#define For(i,a,b) for(int i=a;i<=b;i++)
#define deo(i,a,b) for(int i=a;i>=b;i--)
intl read() {
	intl x=0,k=1;char ch=getchar();
	while(!isdigit(ch)) {if(ch == '-') k=-1;ch=getchar();}
	while(isdigit(ch)) {x=(x<<3)+(x<<1)+(ch^48);ch=getchar();}
	return x*k;
}
intl n, m, vis[N], que[N], ans;
vector<intl> g[N];
int main() {
	n = read(), m = read();
	For(i,1,m) {
		intl u = read(), v = read();
		g[u].push_back(v), g[v].push_back(u);
	}
	For(i,1,n) if(!vis[i]) {
		intl l = 1, r = 1;
		bool flag = true;
		que[1] = i, vis[i] = 1;
		while(l <= r) {
			intl u = que[l++];
			if(g[u].size() != 2) flag = false;
			for(intl v:g[u]) if(!vis[v]) 
				vis[v] = 1, que[++r] = v;
		}
		if(flag) ans++;
	}
	printf("%lld\n",ans);
	return 0;
}

CF1473E

显然,式子为 \(\sum_{i=1}^k w_i - \max w_i + \min w_i\) 我们将 \(-w_i\) 和 \(+w_i\) 视为一种操作,因为我们求最短路,所以到最后一定是取的 \(-\max w_i\) 和 \(+\min w_i\) 因为这样才最小。我们定义 \(dis_{u,0/1/2/3}\) 其中 \(dis_{u,0}\) 表示一个操作都没有使用的最小值,\(dis_{u,1}\) 表示只使用减法的最小值,\(dis_{u,2}\) 表示只使用了加法的最小值,\(dis_{u,3}\) 表示都用了的最小值,那么答案就是 \(dis_{u,3}\)。转移就正常转移。

点击查看代码
#include<bits/stdc++.h>
using namespace std;
#define N 200005
#define intl long long
#define For(i,a,b) for(intl i=a;i<=b;i++)
#define deo(i,a,b) for(intl i=a;i>=b;i--)
intl read() {
	intl x=0,k=1;char ch=getchar();
	while(!isdigit(ch)) {if(ch == '-') k=-1;ch=getchar();}
	while(isdigit(ch)) {x=(x<<3)+(x<<1)+(ch^48);ch=getchar();}
	return x*k;
}
struct node{
	intl u, d, s;
	bool operator < (const node&a) const {
		return d > a.d;
	}
};
intl dis[N][4], n, m;
vector<pair<intl,intl>> g[N];
priority_queue<node> q;
void upd(intl u,intl d,intl s) {
	if(d < dis[u][s]) dis[u][s] = d, q.push({u, dis[u][s], s});
}
void dij() {
	while(q.size()) {
		auto [u,d,s] = q.top();q.pop();
		if(dis[u][s] < d) continue;
		for(auto [v,w]:g[u]) {
			upd(v, w+d, s);
			if(!(s&1)) upd(v, d, s|1);
			if(!(s&2)) upd(v, d+2*w, s|2);
			if(!s) upd(v, d+w, 3); 
		}
	}
}
int main() {
	n = read(), m = read();
	For(i,1,m) {
		intl u = read(), v = read(), w = read();
		g[u].push_back({v, w}), g[v].push_back({u, w});
	} 
	memset(dis, 127, sizeof dis), upd(1, 0, 0);
	dij();
	For(i,2,n) printf("%lld ", dis[i][3]);
	return 0;
}


### [CF126B](https://codeforces.com/problemset/problem/126/B "CF126B") 简单题, 我们考虑 KMP 求的 $nxt_i$ 数组的定义,它定义为当前以 $i$ 结尾的前缀字符串的border 那么就告诉我们,对于 $n$ 的 $nxt_n$ 就一定在前缀中出现,那么就只需要 check 他是否在中间出现,那么显然,我们只需要检查它是否比中间的最大值还大,那么肯定是不会出现的,否则它在中间出现过,如果没有则继续令 $ans = nxt_ans$ 检验下去就可以了,如果最后 $ans = 0$ 则无解,输出 $Just a legend$。 #### 证明 令当前检验的长度为 $ans$,因为 $ans$ 一定是原字符串 $s$ 的 border,所以它一定在前后缀均出现,然后判断是否在中间出现,因为 $nxt_i$ 求的是以 $i$ 结尾的前缀字符串的 border,所以它一定是一个前缀,那么如果存在 $ans \le nxt_i,2 \le i \le n-1$,那么中间就一定有个 border 在前后缀都出现,所以结论成立,证毕。
点击查看代码
#include<bits/stdc++.h>
using namespace std;
#define N 1000005
#define intl long long
#define For(i,a,b) for(intl i=a;i<=b;i++)
#define deo(i,a,b) for(intl i=a;i>=b;i--)
intl read() {
	intl x=0,k=1;char ch=getchar();
	while(!isdigit(ch)) {if(ch == '-') k=-1;ch=getchar();}
	while(isdigit(ch)) {x=(x<<3)+(x<<1)+(ch^48);ch=getchar();}
	return x*k;
}
intl nxt[N], n, mx;
string s;
int main() {
	cin >> s, n = s.size(), s = ' ' + s; 
	For(i,2,n) {
		intl j = nxt[i-1];
		while(j && s[i] != s[j+1]) j = nxt[j];
		if(s[j+1] == s[i]) j ++;
		nxt[i] = j;
		if(i < n) mx = max(mx, nxt[i]);
	}
	intl ans = nxt[n];
	while(ans > mx) ans = nxt[ans];
	if(ans) For(i,1,ans) putchar(s[i]);
	else puts("Just a legend");
	return 0;
}


CF7D

简单题,显然前缀 \(i\) 的贡献等于 \(\frac{i}{2}\) 的贡献 \(+1\),且有贡献当且仅当这个前缀是回文串,然后就做完了,用哈希判断是不是回文串就可以了。

点击查看代码
#include<bits/stdc++.h>
using namespace std;
#define N 5000005
#define intl long long
#define For(i,a,b) for(intl i=a;i<=b;i++)
#define deo(i,a,b) for(intl i=a;i>=b;i--)
intl read() {
	intl x=0,k=1;char ch=getchar();
	while(!isdigit(ch)) {if(ch == '-') k=-1;ch=getchar();}
	while(isdigit(ch)) {x=(x<<3)+(x<<1)+(ch^48);ch=getchar();}
	return x*k;
}
const intl B1 = 233, mod1 = 19260817;
const intl B2 = 131, mod2 = 1000000007; 
intl n, dp[N];
string s;
int main() {
	cin >> s, n = s.size(), s = ' ' + s;
	intl f1 = 0, f2 = 0, r1 = 0, r2 = 0, p1 = 1, p2 = 1, ans = 0;
	For(i,1,n) {
		(f1 += s[i]*p1%mod1) %= mod1, (f2 += s[i]*p2%mod2)%=mod2;
		(r1 = r1*B1+s[i]) %= mod1, (r2 = r2*B2 + s[i]) %= mod2;
		if(f1 == r1 && f2 == r2) dp[i] = dp[i/2] + 1;
		ans += dp[i], (p1 *= B1) %= mod1, (p2 *= B2) %= mod2;
	}
	printf("%lld\n", ans);
	return 0;
}


posted @ 2026-10-07 10:54  shiori123  阅读(3)  评论(0)    收藏  举报