2025国庆Day1

模拟赛

T1

对h离散化,枚举x,分类讨论某些位置淹没后段的个数的变化情况即可

可恶的毒瘤出题人竟然造了一个高度全0的hack

注意特判此时答案为0

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<iomanip>
#include<bits/stdc++.h>
#define int long long
#define jiaa(a,b) {a+=b;if(a>=MOD) a-=MOD;}
#define jian(a,b) {a-=b;if(a<0) a+=MOD;}
using namespace std;
int ksm(int a,int b,int p){
	if(b==0) return 1;
	if(b==1) return a%p;
	int c=ksm(a,b/2,p);
	c=c*c%p;
	if(b%2==1) c=c*a%p;
	return c%p;	
}
inline int read()
{
	int 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*10+ch-48;ch=getchar();}
	return x*f;
}
pair<int,int> st[1000005];
int h[1000005];
vector<int> mh[1000005];
int vis[1000005];
signed main()
{
	//freopen("filename.in", "r", stdin);
	//freopen("filename.out", "w", stdout);
	int n=read();
	int f=0;
	for(int i=1;i<=n;i++){
		st[i].first=read();
		st[i].second=i;
		if(st[i].first) f=1;
	}
	if(!f){
		cout<<0<<'\n';
		return 0;
	}
	sort(st+1,st+n+1);
	int cnt=0,las=-1;
	for(int i=1;i<=n;i++){
		if(st[i].first!=las) cnt++;
		h[st[i].second]=cnt;
		las=st[i].first;
	}
	for(int i=1;i<=n;i++){
		mh[h[i]].push_back(i);
	}
	int ans=1;
	int maxx=1;
	vis[0]=vis[n+1]=1;
	for(int i=1;i<=cnt;i++){
		for(auto ed:mh[i]){
			if(vis[ed-1]==0&&vis[ed+1]==0) ans++;
			else if(vis[ed-1]==1&&vis[ed+1]==1) ans--;
			vis[ed]=1;
		}
//		cout<<ans<<'\n';
		maxx=max(maxx,ans);
	}
	cout<<maxx<<'\n';
	return 0;
}

T2

数位DP

先考虑L==R的dp

套上数位DP

记忆化 or 递推

注意判前导 0

#include <bits/stdc++.h>
#define N 50005
#define K 105 
using namespace std;

const int mod = 1000000007;
inline int qmod(int x) { return x<mod?x:x-mod; }
inline void qadd(int &x, int y) { (x+=y)>=mod?(x-=mod):0; }

char L[N], R[N];
int k, dp[2][N][K];
int tenc[N], upc[N];

int DP(char *T, int d, int sum, bool up, bool zero) {
	int ans = 0;
	if (d < 0) {
		return sum == -2;
	}
	if (!zero && dp[up][d][sum+2] != -1) {
		return dp[up][d][sum+2];
	} 
	int mx = up?T[d]-'0':9;
	for (int i = 0; i <= mx; i++) {
		bool new_up = up&&(i==mx), new_zero = zero&&(i==0);
		if (sum >= 0) {
			int new_sum = (sum*10+i)%k;
			if (new_sum == 0) {
				qadd(ans, DP(T, d-1, -2, new_up, new_zero));
			}
			qadd(ans, DP(T, d-1, new_sum, new_up, new_zero));
		} else if (sum == -1) {
			if (!new_zero) {
				qadd(ans, DP(T, d-1, i%k, new_up, new_zero));
				if (i%k == 0) {
					qadd(ans, DP(T, d-1, -2, new_up, new_zero));
				}
			}
			qadd(ans, DP(T, d-1, -1, new_up, new_zero));
		} else if (sum == -2) {
			qadd(ans, DP(T, d-1, -2, new_up, new_zero));
		} 
	}
	if (!zero) dp[up][d][sum+2] = ans;
	return ans;
}

int calc(char *T, int len) {
	memset(dp, -1, sizeof(dp));
	
	int ans = DP(T, len-1, -1, true, true);
	return ans;
}

void solve() {
	scanf("%s %s %d", L, R, &k);
	int lenL = strlen(L), lenR = strlen(R);
	reverse(L, L+lenL); 
	reverse(R, R+lenR);
	
	for (int i = 0; i < lenL; i++) {
		if (L[i] != '0') {
			L[i]--; break;
		} 
		L[i] = '9';
	}
	if (L[lenL-1] == '0') --lenL;
	
	int ans = qmod(calc(R,lenR)-calc(L,lenL)+mod);
	printf("%d\n", ans); 
}

int main() {
	int ttt; scanf("%d", &ttt);
	while (ttt--) solve();
	return 0;
} 

T3

把从a->b的链提取并重新编号

发现在这条链上,a,b若有人走进子树,两人永远不会相撞

预处理链上的点走进子树还能走多远和链上的前缀和

从相撞时的答案倒推出起点的答案

可用st表做到O(logn)的更新答案

也可O(1)更新答案

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<iomanip>
#include<bits/stdc++.h>
#define int long long
#define jiaa(a,b) {a+=b;if(a>=MOD) a-=MOD;}
#define jian(a,b) {a-=b;if(a<0) a+=MOD;}
using namespace std;
int ksm(int a,int b,int p){
	if(b==0) return 1;
	if(b==1) return a%p;
	int c=ksm(a,b/2,p);
	c=c*c%p;
	if(b%2==1) c=c*a%p;
	return c%p;	
}
inline int read()
{
	int 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*10+ch-48;ch=getchar();}
	return x*f;
}
vector<pair<int,int> > tu[500005];
int id[500005],cnt,sum[500005],maxdep[500005],st1[500005][25],st2[500005][25];
bool dfs(int x,int fa,int go){
	if(x==go){
		id[++cnt]=x;
		sum[cnt]=0;
		return true;
	}
	for(auto [ed,w]:tu[x]){
		if(ed==fa) continue;
		if(dfs(ed,x,go)){
			id[++cnt]=x;
			sum[cnt]=sum[cnt-1]+w;
			return true;
		}
	}
	return false;
}
int ans(int x,int fa){
	int maxx=0;
	for(auto [ed,w]:tu[x]){
		if(ed==fa) continue;
		maxx=max(maxx,w+ans(ed,x));
	}
	return maxx;
}
int query1(int l,int r){
	int logg=__lg(r-l+1);
	return max(st1[l][logg],st1[r-(1<<logg)+1][logg]);
}
int query2(int l,int r){
	int logg=__lg(r-l+1);
	return max(st2[l][logg],st2[r-(1<<logg)+1][logg]);
}
signed main()
{
	int n=read(),a=read(),b=read();
	for(int i=1;i<n;i++){
		int u=read(),v=read(),w=read();
		tu[u].push_back({v,w});
		tu[v].push_back({u,w});
	}
	dfs(b,0,a);
	for(int i=1;i<=cnt;i++){
//		cout<<id[i]<<'\n';
		for(auto [ed,w]:tu[id[i]]){
			if(ed!=id[i-1]&&ed!=id[i+1]) maxdep[i]=max(maxdep[i],w+ans(ed,id[i]));
		}
//		cout<<maxdep[i]<<'\n';
	}
	for(int i=1;i<=cnt;i++){
		st1[i][0]=sum[i]+maxdep[i];
		st2[i][0]=sum[cnt]-sum[i]+maxdep[i];
	}
	for(int i=1;i<=20;i++){
		for(int j=1;j<=cnt;j++){
			if(j+(1<<(i-1))<=cnt) st1[j][i]=max(st1[j][i-1],st1[j+(1<<(i-1))][i-1]);
		}
	}
	for(int i=1;i<=20;i++){
		for(int j=1;j<=cnt;j++){
			if(j+(1<<(i-1))<=cnt) st2[j][i]=max(st2[j][i-1],st2[j+(1<<(i-1))][i-1]);
		}
	}
	int ans=0;
	if(cnt%2==0) ans=query1((cnt+1)/2,(cnt+1)/2)-query2((cnt+1)/2+1,(cnt+1)/2+1);
	else ans=query2((cnt+1)/2+1,(cnt+1)/2+1)-query1((cnt+1)/2,(cnt+1)/2);
	int l=(cnt+1)/2,r=(cnt+1)/2+1;
	int nw=cnt%2;
	while(1){
		if(!nw){
			r++;
			ans=max(-ans,query2(r,r)-query1(l,r-1));
		}
		else{
			l--;
			ans=max(-ans,query1(l,l)-query2(l+1,r));	
		}
//		cout<<l<<' '<<r<<'\n';
		nw++;
		nw%=2;
		if(l<=1&&r>=cnt) break;
//		cout<<ans<<'\n';
	}
	cout<<ans<<'\n';
	return 0;
}

T4

恶心数论

n=2可直接构造

image

最后得出结论:

对x质因数分解

有效质因数个数为m

当且仅当m>=n时,有解

对所有质因数排序

ai=i*x/pi

这里一定有pi>i,因此pi不是i的质因数

复杂度O(sqrt(n))

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<iomanip>
#include<bits/stdc++.h>
#define int long long
#define jiaa(a,b) {a+=b;if(a>=MOD) a-=MOD;}
#define jian(a,b) {a-=b;if(a<0) a+=MOD;}
using namespace std;
int zyz[1000005],cn=0;
signed main()
{
	//freopen("filename.in", "r", stdin);
	//freopen("filename.out", "w", stdout);
	ios::sync_with_stdio(false);
	cin.tie(0),cout.tie(0);
	int T;
	cin>>T;
	while(T--){
		int n,x;
		cin>>n>>x;
		if(n==2){
			cout<<2*x<<' '<<x<<'\n';
			continue;
		}
		if(n>20){
			cout<<-1<<'\n';
			continue;
		}
		int nx=x;
		cn=0;
		for(int i=2;i*i<=x&&i<=1e7;i++){
			if(x%i==0){
				zyz[++cn]=i;
				while(x%i==0) x/=i;
			}
			
		}
		if(x>1) zyz[++cn]=x;
//		for(int i=1;i<=cn;i++) cout<<zyz[i]<<'\n';
		if(cn<n) cout<<-1;
		else for(int i=1;i<=n;i++) cout<<i*nx/zyz[i]<<' ';
		cout<<'\n';
	}
	return 0;
}

搜索

记忆化搜索(其实是DP)

如T2

例:CF628D

求[l,r]=[1,r]-[1,l-1]

CF1734F

观察可得对于编号的二进制

每次在前面加一个1,反转一次

于是sk=(p(k)%2)

p(k)表示k二进制下1的个数

题目转化成p(i^(i+n))%2==0的个数

二进制数位DP

注意进位问题

双向搜索

n=40左右使用

复杂度O(2^(n/2))

CF1767E

对相邻两个点的颜色建图连边

得到的图的最小边覆盖即为答案(自环则这个点必选)

众所不周知求最小边覆盖等价于最大独立集

折半搜索经典应用

小火车

没听懂

网格图BFS

(图论?)

CF1613E

结合博弈

考虑建出博弈图

拓扑排序

省选 2023 过河卒

思路差不多

根据题目模拟

posted @ 2025-10-02 19:01  gbrrain  阅读(4)  评论(0)    收藏  举报