多校A层冲刺NOIP2024模拟赛19

讲个笑话:

(讨论时间)

huge:(叹气)这讨论啊,就是改不了,这换了铃声了,也没……

众人:现在是讨论时间啊。

huge:(停顿)那刚才大课间那会哇啦哇啦的……

图书管理

简要题意

给定一个长度为n(n104)的排列,求l=1nr=ln[rl]l×r×fl,r

solution

签到题,但我ccx被卡了。

部分分是对顶堆、主席树之类的带log做法。

枚举中位数,假设当前枚举到i,然后将大于它的数的记为1,小于它的数的记为-1,求前缀和s,如果1lirn能产生贡献时当且仅当srsl1=0

直接做就完了,用数组求常数较小,可以直接过。

点此查看代码
#include<bits/stdc++.h>
#include<bits/extc++.h>
// #include<sys/timeb.h>
using namespace __gnu_pbds;
using namespace std;
// struct timeb timer;
#define rep(i,s,t,p) for(int i = s;i <= t;i += p)
#define drep(i,s,t,p) for(int i = s;i >= t;i -= p)
#ifdef LOCAL
FILE *InFile = freopen("in.in","r",stdin),*OutFile = freopen("out.out","w",stdout);
// FILE *ErrFile = freopen("err.err","w",stderr);
#else
FILE *InFile = freopen("book.in","r",stdin),*OutFile = freopen("book.out","w",stdout);
#endif
using ll = long long;using ull = unsigned long long;
using db = double;using ldb = long double;
const int N = 1e4 + 10;
int n,a[N];
namespace IO{
char buf[1<<23],*p1,*p2;
#define gc() (p1==p2&&(p2=(p1=buf)+fread_unlocked(buf,1,1<<23,stdin),p1==p2)?EOF:*p1++)
#define pc putchar_unlocked
template<class T>
inline void read(T &x){
x = 0;
char s = gc();
for(;s < '0' || s > '9';s = gc());
for(;'0' <= s && s <= '9';s = gc()) x = (x<<1)+(x<<3)+(s^48);
}
template<class T,class... Args>
inline void read(T &x,Args&... argc){read(x);read(argc...);}
template<class T>
inline void write(T x){
static int sta[20],top = 0;
do{sta[++top] = x%10,x /= 10;}while(x);
do{pc(sta[top--]+'0');}while(top);
}
inline void write(char x){pc(x);}
template<class T,class... Args>
inline void write(T x,Args... argc){write(x);write(argc...);}
}using namespace IO;
int tp[N<<2];
inline void solve(){
ll ans = 0;
read(n);rep(i,1,n,1) read(a[i]);
rep(l,1,n,1){
int tot1 = 0,tot2 = 0;
queue<int> q;
rep(r,l,n,1){
tot1 += (a[r] > a[l]),tot2 += (a[r] < a[l]);
tp[tot1-tot2+n] += r;
}
tot1 = tot2 = 0;
drep(j,l,1,1){
tot1 += a[j] > a[l],tot2 += a[j] < a[l];
ans += 1ll*j*tp[tot2-tot1+n]*a[l];
}
tot1 = tot2 = 0;
rep(r,l,n,1){
tot1 += (a[r] > a[l]),tot2 += (a[r] < a[l]);
tp[tot1-tot2+n] = 0;
}
}
write(ans,'\n');
}
signed main(){
// cin.tie(nullptr)->sync_with_stdio(false);
solve();
}

两棵树

简要题意

给你两棵大小为n(n2×105)树,一个节点有12的概率出现在一棵树中,有12的概率出现在另一棵树中,求两棵树连通块个数乘积的期望数。

solution

考虑到连通块数=剩余的点数-剩余的边数,则贡献X×Y可以拆成4部分,为×××+×

  1. ×的贡献。

    考虑在T中选择点xU中选择点y。若x=y,则贡献为0,反之,贡献为14。所以总贡献为Cn24

  2. ×的贡献。

    考虑T中留下边(x,y)U中留下点k,则当x=ky=k时贡献为0,反之贡献为18。所以总贡献为(n1)×(n2)8

  3. ×的贡献。

    考虑T中留下(x,y)U中留下(u,v),当x,y,u,v中存在两个相同时,贡献为0,反之,贡献为116

    考虑如何计算,可以枚举(x,y),统计符合条件的(u,v)个数,就是n1degUxdegUy+[U中存在(u,v)=(x,y)]

点此查看代码
#include<bits/stdc++.h>
using namespace std;
#define rep(i,s,t,p) for(int i = s;i <= t;i += p)
#define drep(i,s,t,p) for(int i = s;i >= t;i -= p)
#ifdef LOCAL
FILE *InFile = freopen("in.in","r",stdin),*OutFile = freopen("out.out","w",stdout);
#else
FILE *InFile = freopen("tree.in","r",stdin),*OutFile = freopen("tree.out","w",stdout);
#endif
using ll = long long;using ull = unsigned long long;
using db = double;using ldb = long double;
constexpr int N = 2e5 + 10,mod = 998244353;
struct node{int x,y;}a[N],b[N];
int n,d[N];
inline int power(int a,int b,int mod){
int res = 1;
for(;b;b >>= 1,a = 1ll*a*a%mod)
if(b&1) res = 1ll*res*a%mod;
return res;
}
inline int Inv(int x){return power(x,mod-2,mod);}
set<int> st[N];
inline void solve(){
cin>>n;
rep(i,1,n-1,1) cin>>a[i].x>>a[i].y;
rep(i,1,n-1,1)
cin>>b[i].x>>b[i].y,
st[b[i].x].insert(b[i].y),st[b[i].y].insert(b[i].x),
d[b[i].x]++,d[b[i].y]++;
int ans = 0;
ans = (ans + 1ll*n*(n-1)%mod*Inv(4)%mod)%mod;
ans = (ans - 1ll*(n-1)%mod*(n-2)%mod*Inv(4)%mod + mod) % mod;
if(n >= 4) rep(i,1,n-1,1)
ans = (ans + 1ll*(n-1-d[a[i].x]-d[a[i].y] + st[a[i].x].count(a[i].y))*Inv(16)%mod)%mod;
cout<<ans<<'\n';
}
signed main(){
cin.tie(nullptr)->sync_with_stdio(false);
solve();
}

函数

简要题意

定义一个函数f(x)=(xa)b,其中a,b为给定的参数。

有一个长度为n(n106)的序列x,给出q(q106)次询问,每次给定a,b,问是否存在i[1,n),满足f(xi)×f(xi+1)0

solution

简单题,可是赛时没想到用Trie。

考虑求出xia最大的位置maxpos和最小的位置minpos,如果f(xmaxpos)×f(xminpos)>0显然无解。

反之,考虑二分,每次取中点mid,易知f(xmid)肯定与f(xmaxpos)f(xminpos)中的一个异号,所以f(xmaxpos)f(xminpos)f(xmid)中必然有一对异号,正确性显然。

时间复杂度O(nlogV+q×(logn+logV))2e8略微卡常。

点此查看代码
#include<bits/stdc++.h>
using namespace std;
#define rep(i,s,t,p) for(int i = s;i <= t;i += p)
#define drep(i,s,t,p) for(int i = s;i >= t;i -= p)
#ifdef LOCAL
FILE *InFile = freopen("in.in","r",stdin),*OutFile = freopen("out.out","w",stdout);
#else
FILE *InFile = freopen("fun.in","r",stdin),*OutFile = freopen("fun.out","w",stdout);
#endif
using ll = long long;using ull = unsigned long long;
using db = double;using ldb = long double;
namespace IO{
char buf[1<<23],*p1,*p2;
#define gc() (p1==p2&&(p2=(p1=buf)+fread_unlocked(buf,1,1<<23,stdin),p1==p2)?EOF:*p1++)
#define pc putchar_unlocked
template<class T>
inline void read(T &x){
x = 0;
char s = gc();
for(;s < '0' || s > '9';s = gc());
for(;'0' <= s && s <= '9';s = gc()) x = (x<<1)+(x<<3)+(s^48);
}
template<class T,class... Args>
inline void read(T &x,Args&... argc){read(x);read(argc...);}
template<class T>
inline void write(T x){
static int sta[20],top = 0;
do{sta[++top] = x%10,x /= 10;}while(x);
do{pc(sta[top--]+'0');}while(top);
}
inline void write(char x){pc(x);}
template<class T,class... Args>
inline void write(T x,Args... argc){write(x);write(argc...);}
}using namespace IO;
const int N = 1e6 + 10,V = 1e9 + 10,LV = 29;
int n,q,x[N];
struct Trie{
int tree[N*30][2],tot,en[N*30],ex[N*30];
inline void insert(int x,int pos){
int p = 0;
drep(i,LV,0,1){
bool k = (x>>i)&1;
if(!tree[p][k]) tree[p][k] = ++tot;
p = tree[p][k];
}
if(!en[p]) en[p] = pos;
ex[p] = max(ex[p],pos);
}
inline int qryn(int x){
int p = 0;
drep(i,LV,0,1){
bool k = (x>>i)&1;
if(tree[p][k]) p = tree[p][k];
else p = tree[p][!k];
}
return en[p];
}
inline int qryx(int x){
int p = 0;
drep(i,LV,0,1){
bool k = (x>>i)&1;
if(tree[p][!k]) p = tree[p][!k];
else p = tree[p][k];
}
return ex[p];
}
}trie;
inline bool cmp(int x,int y){return (x<=0&&y>=0)||(x>=0&&y<=0);}
inline void solve(){
read(n,q);rep(i,1,n,1) read(x[i]);
rep(i,1,n,1) trie.insert(x[i],i);
while(q--){
int a,b;read(a,b);
int l = trie.qryn(a);int r = trie.qryx(a);
if(l > r) swap(l,r);
auto f = [&](int pos){return (x[pos]^a)-b;};
if(!cmp(f(l),f(r))){puts("-1");continue;}
int pos1 = l,pos2 = r,ans = 0;
int f1 = f(pos1),f2 = f(pos2);
bool flag = true;
while(l <= r){
int mid = (l + r) >> 1;
if(cmp(f2,f(mid))) flag = false,ans = mid,l = mid + 1;
else flag = true,ans = mid,r = mid - 1;
}
if(flag) write(ans-1,'\n');
else write(ans,'\n');
}
}
signed main(){solve();}

编辑

简要题意

给定k(k30)和两个字符串S,T(|S|,|T|5×104)i[0,k],求出T中多少个非空子串与S的编辑距离恰好为i

solution

严格弱化版:[BJOI2015] 隐身术

部分分直接暴力DP。正解好像很难的样子,不会。

30pts

枚举 T 的某一子串进行编辑距离求解的DP,具体状态为让 A 变成 B,现在只考虑 A[1:i] 变成 B[1:j] 的编辑距离为 f[i][j],转移时考虑删除,添加,修改第 i+1 个位置即可,时间复杂度为 O(n4)​。

100pts

枚举每个后缀,fi,j 表示最大的 x,使得 S[1:x]T[1:x+j] 可以在 i 次编辑内得到,显然若 x 可以,所有x0xS[1:x0]T[1:x0+j] 都可以在 i 次编辑内得到。

考虑如何转移,先考虑做完第 j 次编辑操作后往外延申,可以延申的即为 S 的一个后缀和 T 的一个后缀的最长公共前缀,即fi,j=fi,j+LCP(S[fi,j+1:|S|],T[fi,j+j+1..:|T|]),随后我们可以通过对fi+1,j1,fi+1,j,fi+1,j+1 三项进行转移,即考虑下一次的编辑的具体操作是删除添加还是修改。

每次要算的两个后缀的前缀下标不会差超过 k,因此一共至多求 O(nk) 次 LCP,可以利用二分+ hash 的方式解决。

记录每个后缀中 fi,j=|S| 的那些状态,即可计算出最终答案,时间复杂度为 O(nk2+nklogn)

P

image

posted @   CuFeO4  阅读(36)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 一个费力不讨好的项目,让我损失了近一半的绩效!
· 清华大学推出第四讲使用 DeepSeek + DeepResearch 让科研像聊天一样简单!
· 实操Deepseek接入个人知识库
· 易语言 —— 开山篇
· CSnakes vs Python.NET:高效嵌入与灵活互通的跨语言方案对比
点击右上角即可分享
微信分享提示