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可直接构造

最后得出结论:
对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
结合博弈
考虑建出博弈图
拓扑排序
思路差不多
根据题目模拟

浙公网安备 33010602011771号