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

\(\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

\(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

\(n\leq 10^5\)。
额,貌似是 \(\text{SAM}\) 板子,科技树没有点...
也可以用 \(\text{SA}\) 去做。

浙公网安备 33010602011771号