2023年石门中学NOIP模拟测试(2023.10.16)

T1

image

\(\sum n\leq 2\times 10^6,x\leq 10^9\)

简单来说,让你在给出的序列中构造差分序列不出现 \(x\) 的一组解。

签到题。

\(x\) 分类讨论,排个序,调整一下,注意 \(x=0\) 时 交叉构造以及 \(a_i=0\) 情况即可。

Code
#include<bits/stdc++.h>
#define il inline 
#define rint register int
#define ll long long
#define pii pair<int,int>
using namespace std;
const int N=1e5+10,INF=2147483647;
char *p1,*p2,buf[N];
#define nc() (p1==p2 && (p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++)
#define gc() getchar()
il int rd(){
	int x=0,f=1;
	char ch=gc();
	while(!isdigit(ch)){if(ch=='-')f=-1;ch=gc();}
	while(isdigit(ch))x=(x<<3)+(x<<1)+(ch^48),ch=gc();
	return x*f;
}
int n,m;
int a[N],ans[N];
struct dat{
	int s,id;
}g[N];
void Main(){
	n=rd(),m=rd();
	for(int i=1; i<=n; ++i)a[i]=rd();
	if(m==0){
		sort(a+1,a+1+n,[&](int &a,int &b){return a<b;});
		int cnt=0;
		for(int i=1; i<=n; ++i){
			int now=i;
			while(now<n&&a[now]==a[now+1])++now;
			g[++cnt].s=now-i+1;g[cnt].id=i;
			i=now;
		}
		sort(g+1,g+1+cnt,[&](dat x,dat y){return a[x.id]<a[y.id];});
		bool fl=1;
		for(int i=1; i<=cnt; ++i){
			if(n-g[i].s<g[i].s-1+(a[g[i].id]==0)){
				fl=0;break;
			}
		}
		if(fl){
			puts("yes");
			priority_queue<pii>q;
			for(int i=1; i<=cnt; ++i)q.push({g[i].s,a[g[i].id]});//cout<<a[g[i].id]<<' '<<g[i].s<<endl;
			int tot=0;
			while(q.size()>=2){
				pii x=q.top();q.pop();
				pii y=q.top();q.pop();
				//printf("%d %d ",x.second,y.second);
				if(ans[tot]==x.second)swap(x,y);
				ans[++tot]=x.second,ans[++tot]=y.second;
				--x.first,--y.first;
				if(y.first)q.push(y);
				if(x.first)q.push(x);
			}
			if(!q.empty()){
				int x=q.top().second,fl=0;
				ans[tot+1]=-INF;
				for(int i=0; i<=tot; ++i){
					if(i)printf("%d ",ans[i]);
					if(ans[i]!=x&&ans[i+1]!=x&&!fl){
						printf("%d ",x);
						fl=1;
					}
				}
			}else{
				for(int i=1; i<=tot; ++i){
					printf("%d ",ans[i]);
				}
			}
			puts("");
		}else{
			puts("no");
		}
	}
	else{
		if(m<0)sort(a+1,a+1+n,[&](int a,int b){return a<b;});
		else sort(a+1,a+1+n,[&](int a,int b){return a>b;});
		int fl=0;
		for(int i=2; i<=n; ++i){
			if(a[1]-a[i]!=m&&a[i]!=m)fl=i;
		}
		if(a[1]!=m){
			puts("yes");
			for(int i=1; i<=n; ++i)printf("%d ",a[i]);
			puts("");
		}
		else if(fl){
			puts("yes");
			printf("%d ",a[fl]);
			for(int i=1; i<=n; ++i)if(i!=fl)printf("%d ",a[i]);
			puts("");
		}else{
			puts("no");
		}
	}
}
signed main(){
	freopen("dif.in","r",stdin);
	freopen("dif.out","w",stdout);
	int T=rd();
	while(T--)Main();
	return 0;
}

T2

image

\(n\leq 10^6\)

啊?一眼淀粉质板子。好,然后你就发现 \(n\log^2 n\) oj 上$ 3s$ 跑不过 \(10^6\),尊嘟假嘟 o_0?

还能 \(n\log n\) 啊,那没事了。

\(\log^2\) 的:

Code
#include<bits/stdc++.h>
#define il inline 
#define rint register int
#define int long long
#define pii pair<int,int>
#define lb(i) (i&-i)
#pragma GCC optimize("O3")
#pragma GCC optimize("Ofast")
#pragma GCC optimize("inline")
using namespace std;
const int N=1e6+10,INF=2147483647,mod=1e9+7;
char *p1,*p2,buf[N];
#define nc() (p1==p2 && (p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++)
#define gc() getchar()
il int rd(){
	int x=0,f=1;
	char ch=gc();
	while(!isdigit(ch)){if(ch=='-')f=-1;ch=gc();}
	while(isdigit(ch))x=(x<<3)+(x<<1)+(ch^48),ch=gc();
	return x*f;
}
int n;
int a[N],ran[N],len;
vector<int>e[N];
int rt,S,siz[N],rt_mx;
bool vis[N];
il void Dfs_rt(int x,int f){
	siz[x]=1;
	int mx=0;
	for(auto y:e[x]){
		if(y==f||vis[y])continue;
		Dfs_rt(y,x);
		siz[x]+=siz[y];
		mx=max(mx,siz[y]);
	}
	mx=max(mx,S-siz[x]);
	if(mx<rt_mx)rt_mx=mx,rt=x;
}
vector<pii>P,OP;
il void get_dis(int x,int f,int dep,int val){
	P.push_back({dep,lower_bound(ran+1,ran+1+len,val)-ran});
	for(auto y:e[x]){
		if(y==f||vis[y])continue;
		get_dis(y,x,dep+1,max(val,a[y]));
	}
}
int sum[N],g[N],ss[N];
il void add(int x,int y,int fl){
	for(int i=x; i; i-=lb(i))(sum[i]+=fl*(ran[x]-y)+mod)%=mod;
	for(int i=x; i<=len; i+=lb(i))(g[i]+=fl+mod)%=mod,(ss[i]+=fl*y+mod)%=mod;
}
il int query(int x){
	int s=0;for(int i=x; i<=len; i+=lb(i))(s+=sum[i])%=mod;
	return s;
}
il int query2(int x){
	int s=0;for(int i=x; i; i-=lb(i))(s+=g[i])%=mod;return s;
}
il  int que(int x){
	int s=0;for(int i=x; i; i-=lb(i))(s+=ss[i])%=mod;return s;
}
int ans;
void solve(int x){
//	cout<<"RT"<<rt<<endl;
	Dfs_rt(rt,0);
	vis[x]=1;
	int tot=0;
	OP.clear();
	for(int y:e[x]){
		if(vis[y])continue;
		P.clear();
		get_dis(y,x,1,max(a[y],a[x]));
		for(auto t:P){
			(ans+=ran[t.second]-t.first+mod)%=mod;
	//		cout<<ans<<endl;
			int s1=query(t.second),s2=query2(t.second-1);//s2:前面<自己 num     s1: >= sum
			(ans+=s1-(tot-s2+mod)*t.first%mod+mod)%=mod;
	//		cout<<ans<<endl;
			(ans+=s2*(ran[t.second]-t.first+mod)%mod-que(t.second-1)+mod)%=mod;
		//	cout<<t.first<<' '<<ran[t.second]<<' '<<ans<<' '<<s1<<' '<<s2<<endl;
		}
		for(auto t:P)
		add(t.second,t.first,1),OP.push_back(t);
		tot+=P.size();
	}
	for(auto t:OP)add(t.second,t.first,-1);
	for(auto y:e[x]){
		if(vis[y])continue;
		rt_mx=INF,S=siz[y];
		Dfs_rt(y,x);
		solve(rt);
	}
}
void Main(){
	n=rd();
	for(int i=1; i<=n; ++i)ran[i]=a[i]=rd();
	sort(ran+1,ran+1+n);
	len=unique(ran+1,ran+1+n)-ran-1;
	for(int u,v,i=1; i<n; ++i){
		u=rd(),v=rd();
		e[u].push_back(v);
		e[v].push_back(u);
	}
	S=n,rt_mx=INF;
	Dfs_rt(1,0);
	solve(rt);
	cout<<ans*2%mod;
}
signed main(){
	freopen("travel.in","r",stdin);
	freopen("travel.out","w",stdout);
	int T=1;
	while(T--)Main();
	return 0;
}

\(\log\) 的:

Code
#include<bits/stdc++.h>
#define il inline 
#define rint register int
#define int long long
using namespace std;
const int N=1e6+10,mod=1e9+7;
char *p1,*p2,buf[N];
#define nc() (p1==p2 && (p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++)
#define gc() getchar()
il int rd(){
	int x=0,f=1;
	char ch=gc();
	while(!isdigit(ch)){if(ch=='-')f=-1;ch=gc();}
	while(isdigit(ch))x=(x<<3)+(x<<1)+(ch^48),ch=gc();
	return x*f;
}
int n;
struct dat{
	int id,s;
}a[N];
vector<int>e[N];
int siz[N],S[N],fa[N],sum[N];
bool vis[N];
int fd(int x){return (x==fa[x])?x:fa[x]=fd(fa[x]);}
void merge(int x,int y){
	int fx=fd(x),fy=fd(y);
	if(fx==fy)return;
	siz[fy]+=siz[fx];
	fa[fx]=fy;
}
int ans;
void dfs(int x,int f){
	S[x]=1;
	for(int y:e[x]){
		if(y==f)continue;
		dfs(y,x);
		S[x]+=S[y];
		ans-=S[y]*(n-S[y])%mod;
		ans=(ans+mod)%mod;
	}
	
}
void Main(){
	n=rd();
	for(int i=1; i<=n; ++i)a[i].s=rd(),a[i].id=i,siz[i]=1,fa[i]=i;
	for(int u,v,i=1; i<n; ++i){
		u=rd(),v=rd();
		e[u].push_back(v);
		e[v].push_back(u);
	}
	dfs(1,0);
	sort(a+1,a+1+n,[&](dat &a,dat &b){return a.s<b.s;});
	for(int i=1; i<=n; ++i){
		for(int y:e[a[i].id]){
			if(vis[y]){
				ans+=a[i].s*siz[fd(a[i].id)]%mod*siz[fd(y)]%mod;
				ans%=mod;
				merge(a[i].id,y);
			}
		}
		vis[a[i].id]=1;
	}
	cout<<ans*2%mod;
}
signed main(){
	freopen("travel.in","r",stdin);
	freopen("travel.out","w",stdout);
	int T=1;
	while(T--)Main();
	return 0;
}

发现自己 \(\text{Implement}\) 一坨屎...

T3

翻译一下:你有一个长度为 \(n\) 的字符串由 \(N,O,I,P,?\) 组成,其中 \(?\) 可以被替换成任意其他四个。现在每个字符串有一个权值 \(val=\sum\limits_{i=1}^{n-1}f(s_i,s_{i+1})\),其中 \(f\) 会以 \(4\times 4\) 表格给出,现在让我们求出字符串权值大于等于 \(x\) 的字符串中字典序第 \(k\) 小的,如果这个串不存在,输出 \(-1\)

\(n,k\leq 10^3,x\leq 10^9,f_{i,j}\leq 10^4\)

输麻了,想不到 \(k\) 短路,一直以为是 \(\text{dp}\)。其实这题暴力乱搞+神仙剪枝就过了...

首先这个图本质上就是要我们求 \(\text{DAG}\) 图上 \(k\) 短路,既然是 \(k\) 短路,那我们可以暴力 \(dfs\),时间复杂度 \(O(4^nk)\)。思考我们上述算法瓶颈在哪?无非是在无关状态上(也就是那些不会有权值 \(\ge x\)) 的状态上浪费太多时间,那我们不妨设计一个类似预估函数,告诉我们当前是否有必要执行搜索,这便是所谓的 \(\text{A*}\)

现在我们考虑如何设计这个函数,正确性得到保障的话,就要不能放过任何可能的解。那我们设计这个函数为:从当前状态继续往下搜索,其所有可能解中的最大值为多少。

假如我们可以 \(O(1)\) 解决上述问题,这时我们枚举 \(k\) 次找到第 \(k\) 个合法解,每次枚举到一组合法解的时间复杂度从 \(O(4^n)\) 变成了 \(O(n)\),于是我们就解决了原问题。

现在只剩怎么求这个函数,这实际上是个类似后缀 \(\text{ddp}\) 的东西,设计广义矩阵转移就完事了。

Code
#include<bits/stdc++.h>
#define il inline 
#define rint register int
#define int long long
using namespace std;
const int N=1e3+10,INF=1ll<<60;
char *p1,*p2,buf[N];
#define nc() (p1==p2 && (p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++)
#define gc() getchar()
il int rd(){
	int x=0,f=1;
	char ch=gc();
	while(!isdigit(ch)){if(ch=='-')f=-1;ch=gc();}
	while(isdigit(ch))x=(x<<3)+(x<<1)+(ch^48),ch=gc();
	return x*f;
}
int n,m,k;
char s[N],ans[N];
struct Mat{
	int a[4][4];
	Mat(){
		memset(a,-0x3f,sizeof(a));
		for(int i=0; i<4; ++i)a[i][i]=0;
	}
	int query(int x){
		int ans=-INF;
		for(int i=0; i<4; ++i)ans=max(ans,a[x][i]);
		return ans;
	}
	friend Mat operator*(Mat x,Mat y){
		Mat c;
		memset(c.a,-0x3f,sizeof(c.a));
		for(int i=0; i<4; ++i){
			for(int j=0; j<4; ++j){
				for(int k=0; k<4; ++k){
					c.a[i][j]=max(c.a[i][j],x.a[i][k]+y.a[k][j]);
				}
			}
		}
		return c;
	}
}suf[N],base[5],head[5];
int get(char x){
	if(x=='?')return 0;
	if(x=='N')return 1;
	if(x=='O')return 2;
	if(x=='I')return 3;
	if(x=='P')return 4;
}
int tot;
int ord[4]={4,2,1,3};
int id[N];
void dfs(int now,int val){
	if(now>n){
		if(val>=m){
			if(++tot==k){
				printf("%s",(ans+1));
				exit(0);
			}
		}
		return ;
	}
	if(s[now]=='?'){
		for(int i:ord){
			if(val+(now==1?0:base[0].a[id[now-1]-1][i-1])+(head[i]*suf[now+1]).query(i-1)>=m){
				ans[now]="NOIP"[i-1];
				id[now]=i;
				dfs(now+1,val+(now==1?0:base[0].a[id[now-1]-1][i-1]));
			}
		}
	}
	else {
		ans[now]=s[now];
		id[now]=get(s[now]);
		dfs(now+1,val+(now==1?0:base[0].a[id[now-1]-1][id[now]-1]));
	}
}
void Main(){
	n=rd(),m=rd(),k=rd();
	scanf("%s",s+1);
	for(int i=0; i<4; ++i){
		for(int j=0; j<4; ++j)base[0].a[i][j]=rd();
	}
	for(int i=1; i<=4; ++i){
		base[i]=base[0];
		for(int j=0; j<4; ++j){
			for(int k=0; k<4; ++k){
				if(k!=i-1){
					base[i].a[j][k]=-INF;
					head[i].a[j][k]=-INF;
				}else{
					head[i].a[j][k]=0;
				}
			}
		}
	}
	for(int i=n; i>1; --i)
		suf[i]=base[get(s[i])]*suf[i+1];
	dfs(1,0);
	printf("-1");
}
signed main(){
	freopen("perm.in","r",stdin);
	freopen("perm.out","w",stdout);
	int T=1;
	while(T--)Main();
	return 0;
}

T4

image

\(n\leq 10^5\)

额,貌似是 \(\text{SAM}\) 板子,科技树没有点...

也可以用 \(\text{SA}\) 去做。

posted @ 2023-10-16 15:45  J1mmyF  阅读(44)  评论(0)    收藏  举报