文章目录
- 前言
- CF643A Bear and Colors
- CF643B Bear and Two Paths
- CF643C Levels and Regions
- CF643D Bearish Fanpages
- CF643E Bear and Destroying Subtrees
- CF643F Bears and Juice
- CF643G Choosing Ads
前言
毒瘤比赛,三紫二黑(而且感觉G完全有黑的难度)
也受到了下午统练的影响,做了一天qwq
AB很水,CD不错,EFG直接贺
也与我
A奇水
B是可以五分钟做一做的简单构造
C是小清新dp,可以斜优我不想动脑直接分治挂log
D思路不太难想,但写起来是真的恶心
E是标准CF那种令人哭笑不得的“…时…,所以只需要考虑”题,但是dp思想还是不错的
F是诡异的组合题,先找到答案上界再试图证明可以达到
G需要一个前置的小结论,然而我并不会。。。后面线段树快速合并区间的地方也不是很好想
CF643A Bear and Colors
Description\text{Description}Description
Limak 有 nnn 个球,从左到右编号依次为 1…n1 \dots n1…n。同时又有 nnn 种颜色,从编号依次为 1…n1 \dots n1…n。第 iii 个球的编号为 tit_iti。
对于球中每一个固定的段(含有连续元素的集合),可以定义一个主要颜色,即此段中出现次数最多的颜色。在可以有多种主要颜色的情况下,选择编号最小的。
现有 n(n+1)2\dfrac{n(n + 1)}{2}2n(n+1) 个不为空的段。对于每个颜色,你需要输出此颜色作为主要颜色的次数。
n≤5000n\le 5000n≤5000
Solution\text{Solution}Solution
本来还觉得可能得想想,看到数据范围笑了。
直接开桶 n2n^2n2 暴力扫一遍即可。
Description\text{Description}Description
#include<bits/stdc++.h>
using namespace std;
#define ull unsigned long long
#define debug(...) fprintf(stderr,__VA_ARGS__)
const int N=5050;
#define ll long long
inline ll read(){ll x(0),f(1);char c=getchar();while(!isdigit(c)){if(c=='-')f=-1;c=getchar();}while(isdigit(c)) {x=(x<<1)+(x<<3)+c-'0';c=getchar();}return x*f;
}int n,m;
int bac[N],a[N],res,ans[N];
signed main(){
#ifndef ONLINE_JUDGEfreopen("a.in","r",stdin);freopen("a.out","w",stdout);
#endifn=read();for(int i=1;i<=n;i++) a[i]=read();for(int l=1;l<=n;l++){memset(bac,0,sizeof(bac));for(int r=l;r<=n;r++){int o=a[r];++bac[o];if(bac[o]>bac[res]||(bac[o]==bac[res]&&o<res)) res=o;ans[res]++;}}for(int i=1;i<=n;i++) printf("%d ",ans[i]);return 0;
}
/*
*/
CF643B Bear and Two Paths
Description\text{Description}Description
一共有 nnn 个结点,给出互异的四个点 a,b,c,da,b,c,da,b,c,d,请你构造一个边数不超过 kkk 的无向图,使得 aaa 到 bbb、ccc 到 ddd 之间都存在一条哈密尔顿路径,且 a,ba,ba,b 之间和 c,dc,dc,d 之间不能直接连通。
请输出你构造的路径。
4≤n≤10004\le n\le 10004≤n≤1000
Solution\text{Solution}Solution
首先,对于 n=4n=4n=4 的情况,显然无解。
否则,只要找到一种用边最少的方案即可。
手玩发现,可以通过构造 a→c→x→...→y→d→ba\to c\to x\to...\to y\to d\to ba→c→x→...→y→d→b,再加两条 a→xa\to xa→x 和 y→by\to by→b 的边满足要求,总边数是 n+1n+1n+1。
由于从 ccc 走一定要去往 a,ba,ba,b,这都需要加边跳,所以至少加两条边,答案不会少于这个了。
问题得以解决。
Code\text{Code}Code
#include<bits/stdc++.h>
using namespace std;
#define ull unsigned long long
#define debug(...) fprintf(stderr,__VA_ARGS__)
const int N=5050;
#define ll long long
inline ll read(){ll x(0),f(1);char c=getchar();while(!isdigit(c)){if(c=='-')f=-1;c=getchar();}while(isdigit(c)) {x=(x<<1)+(x<<3)+c-'0';c=getchar();}return x*f;
}int n,m;
int x[N],a,b,c,d,vis[N];
signed main(){
#ifndef ONLINE_JUDGEfreopen("a.in","r",stdin);freopen("a.out","w",stdout);
#endifn=read();m=read();a=read();b=read();c=read();d=read();if(n<=4||m<n+1){printf("-1");return 0;}x[1]=a;x[n]=b;x[2]=c;x[n-1]=d;vis[a]=vis[b]=vis[c]=vis[d]=1;int tot=2;for(int i=1;i<=n;i++){if(!vis[i]) x[++tot]=i;}for(int i=1;i<=n;i++) printf("%d ",x[i]);putchar('\n');printf("%d %d ",c,a);for(int i=3;i<=n-2;i++) printf("%d ",x[i]);printf("%d %d\n",b,d);return 0;
}
/*
*/
CF643C Levels and Regions
Description\text{Description}Description
有一种电子游戏,它由 nnn 个关卡组成,每个关卡都被赋予了一个值 tit_iti。
现在,你要将这些关卡分成 kkk 个级别,每个级别 jjj 对应了一段连续的关卡 [lj,rj][l_j,r_j][lj,rj],且必有 lj≤rjl_j\leq r_jlj≤rj。任何一个关卡在且仅在一个级别中。
然后,一名玩家将会从第 111 个关卡,按顺序一直刷到第 nnn 个关卡。当他打到第 iii 个关卡时,设这个关卡所在的级别是 jjj,则他有 ti∑x=ljitx\dfrac{t_i}{\sum\limits_{x=l_j}^{i}t_x}x=lj∑itxti 的概率在111小时内AC这个关卡,然后进入下一关;或者没有 AC 这个关卡(但仍然花了 111 小时),还得再次挑战这个关卡。
你需要找到一种划分方法,使得该玩家期望 AK 该游戏的期望时间最小。输出这个最小的期望时间。
Solution\text{Solution}Solution
一道乍看很吓人但是仔细想想并不难的小清新 dp 题。
有一个期望相关的常用结论:若一件事做成的概率是 ppp,那么做成这件事需要的期望次数是 1p\dfrac{1}{p}p1。
证明:设期望次数为 xxx,讨论第一次做成或者没做成,就有:
x=(p×0+(1−p)×x)+1x=(p\times0+(1-p)\times x)+1x=(p×0+(1−p)×x)+1
移项即可得。
回到本题。
显然不同段之间互相独立。
设 sumi=∑j=1itjsum_i=\sum_{j=1}^i t_jsumi=∑j=1itj。
那么本题 (l,r)(l,r)(l,r) 区间划分成一段完成的期望次数就是:
∑i=lrsumi−suml−1ti\sum_{i=l}^r \frac{sum_i-sum_{l-1}}{t_i}i=l∑rtisumi−suml−1
也就是:
∑i=lrsumiti−suml−1×∑i=lr1ti\sum_{i=l}^r \frac{sum_i}{t_i}-sum_{l-1}\times\sum_{i=l}^r \frac{1}{t_i}i=l∑rtisumi−suml−1×i=l∑rti1
对 ∑i=lrsumiti\sum_{i=l}^r \dfrac{sum_i}{t_i}∑i=lrtisumi 和 ∑i=lr1ti\sum_{i=l}^r \dfrac{1}{t_i}∑i=lrti1 分别求前缀和,我们就可以 O(1)O(1)O(1) 转移了。
然后直观感受可以发现,这个东西是满足决策单调性的。
感性理解一下就是要使全局尽可能小,前面的 ∑i=lrsumiti\sum_{i=l}^r \dfrac{sum_i}{t_i}∑i=lrtisumi 全合起来后是定值,后面多一个元素的时候,∑i=lr1ti\sum_{i=l}^r \dfrac{1}{t_i}∑i=lrti1 变大,那么为了多减一些,suml−1sum_{l-1}suml−1 的值应该相应的变大(或者至少不应该变小),所以转移点有单调性的。
直接上分治即可,时间复杂度 O(nklogn)O(nk\log n)O(nklogn)。
(看题解的大佬这题也可以斜优做把 log 去掉)
Code\text{Code}Code
#include<bits/stdc++.h>
using namespace std;
#define ull unsigned long long
#define debug(...) fprintf(stderr,__VA_ARGS__)
const int N=2e5+100;
#define ll long long
inline ll read(){ll x(0),f(1);char c=getchar();while(!isdigit(c)){if(c=='-')f=-1;c=getchar();}while(isdigit(c)) {x=(x<<1)+(x<<3)+c-'0';c=getchar();}return x*f;
}int n,m;
double sum[N],t[N];
double s1[N],s2[N];
inline double calc(int l,int r){return (s1[r]-s1[l-1])-sum[l-1]*(s2[r]-s2[l-1]);
}
double dp[52][N];
void solve(int k,int l,int r,int tl,int tr){if(l>r) return;int mid=(l+r)>>1,pl(0);for(int i=tl;i<=min(mid-1,tr);i++){double w=dp[k-1][i]+calc(i+1,mid);if(w<dp[k][mid]){dp[k][mid]=w;pl=i;}}solve(k,l,mid-1,tl,pl);solve(k,mid+1,r,pl,tr);return;
}
signed main(){
#ifndef ONLINE_JUDGEfreopen("a.in","r",stdin);freopen("a.out","w",stdout);
#endifn=read();m=read();for(int i=1;i<=n;i++){t[i]=read();sum[i]=sum[i-1]+t[i];s1[i]=s1[i-1]+sum[i]/t[i];s2[i]=s2[i-1]+1.0/t[i];}for(int i=0;i<=m;i++){for(int j=0;j<=n;j++) dp[i][j]=2e18;}dp[0][0]=0;for(int k=1;k<=m;k++) solve(k,1,n,0,n-1);printf("%lf\n",dp[m][n]);return 0;
}
/**/
CF643D Bearish Fanpages
Description\text{Description}Description
给定一个 nnn 个点的基环内向树森林,即给定每个点 iii 的后继 fif_ifi。
(特别地,保证在任意时刻,这个基环内向森林中的环长都 ≥3\boldsymbol{\ge 3}≥3)
在这个限制下,考虑与某个点 iii 距离不超过 111 的点,也就是 iii 本身,iii 的后继 fif_ifi 以及若干个后继为 iii 的点。
不妨假设有 kkk 个点的后继为 iii,则我们需要考虑这 k+2k + 2k+2 个点(这是因为环长 ≥3\ge 3≥3,不会出现重复的点)。
称这 k+2k + 2k+2 个点分别为 i,j0,j1,j2,…,jki, j_0, j_1, j_2, \ldots , j_ki,j0,j1,j2,…,jk(j0j_0j0 为 iii 的后继,j1…kj_{1 \ldots k}j1…k 为后继为 iii 的那 kkk 个点)。
现在假设神秘事件发生了,每个点都会进入一些人,第 iii 个点会进入 tit_iti 个人。
恰好 ⌊tik+2⌋\left\lfloor \frac{t_i}{k+2} \right\rfloor⌊k+2ti⌋ 个人会进入 j0,j1,j2,…,jkj_0, j_1, j_2, \ldots , j_kj0,j1,j2,…,jk 号点(每个点都进入 ⌊tik+2⌋\left\lfloor \frac{t_i}{k+2} \right\rfloor⌊k+2ti⌋ 个人),剩下的 ti−(k+1)⋅⌊tik+2⌋t_i - (k + 1) \cdot \!\left\lfloor \frac{t_i}{k+2} \right\rfloorti−(k+1)⋅⌊k+2ti⌋ 个人会留在点 iii。
你需要依次处理 qqq 个操作:
1 i j
:将 fif_ifi 改为 jjj,即把 iii 的后继变成 jjj。保证仍然满足上文中的条件。
2 i
:计算当神秘事件发生时,第 iii 个点最终会留下多少人。
3
:计算当神秘事件发生时,每个点内最终留下的人数的最小值和最大值。
注意:每次神秘事件发生都是互不影响的。
Solution\text{Solution}Solution
阴间大模拟题。
容易想到,问题可以转化成对亿些集合的集体修改和亿些单点的修改。
全局 min,max\min,\maxmin,max 开两个 set
维护即可。
集体修改考虑懒标记,我用的是线段树维护,对于每个点开一棵以它为父亲的线段树,动态开点插入删除修改瞎做即可。
Code\text{Code}Code
有的地方为了可读性忽略了代码效率,自带 242424 倍常数,成功斩获最劣解
极其屎山,不过看几篇题解似乎都差不多…
#include<bits/stdc++.h>
using namespace std;
#define ull unsigned long long
#define debug(...) fprintf(stderr,__VA_ARGS__)
const int N=1e5+100;
#define ll long long
inline ll read(){ll x(0),f(1);char c=getchar();while(!isdigit(c)){if(c=='-')f=-1;c=getchar();}while(isdigit(c)) {x=(x<<1)+(x<<3)+c-'0';c=getchar();}return x*f;
}int n,m,tim;
ll t[N],w[N],v[N];
int du[N],fa[N];
multiset<ll>mn,mx;#define mid ((l+r)>>1)
struct tree{int ls,rs;ll mn,mx,laz;
}tr[N<<6];
int rt[N],tot;
inline int New(){++tim;++tot;tr[tot].mn=2e18;tr[tot].mx=-2e18;return tot;
}
inline void pushup(int k){++tim;tr[k].mn=min(tr[tr[k].ls].mn,tr[tr[k].rs].mn);tr[k].mx=max(tr[tr[k].ls].mx,tr[tr[k].rs].mx);return;
}
inline void tag(int k,ll v){++tim;if(!k) return;tr[k].laz+=v;tr[k].mn+=v;tr[k].mx+=v;return;
}
inline void pushdown(int k){++tim;ll o=tr[k].laz;tr[k].laz=0;if(!o) return;tag(tr[k].ls,o);tag(tr[k].rs,o);return;
}
void add(int &k,int l,int r,int p,ll v){++tim;if(!k) k=New();if(l==r){tr[k].mn=tr[k].mx=v;return;}pushdown(k);if(p<=mid) add(tr[k].ls,l,mid,p,v);else add(tr[k].rs,mid+1,r,p,v);pushup(k);
}
ll ask(int k,int l,int r,int p,int op=0){++tim;assert(k);if(l==r){ll res=tr[k].mn;if(op) tr[k].mx=-2e18,tr[k].mn=2e18;return res;}pushdown(k);ll res(0);if(p<=mid) res=ask(tr[k].ls,l,mid,p,op);else res=ask(tr[k].rs,mid+1,r,p,op);pushup(k);return res;
}
void change(int k,int l,int r,int p,ll v){++tim;assert(k);if(l==r){tr[k].mn+=v;tr[k].mx+=v;return;}pushdown(k);if(p<=mid) change(tr[k].ls,l,mid,p,v);else change(tr[k].rs,mid+1,r,p,v);pushup(k);return;
}
void upd(int x,ll w){++tim;change(rt[fa[x]],1,n,x,w);return;
}set<int>s;
ll sef[N];
signed main(){
#ifndef ONLINE_JUDGEfreopen("a.in","r",stdin);freopen("a.out","w",stdout);
#endiftr[0].mn=2e18;tr[0].mx=-2e18;n=read();m=read();for(int i=1;i<=n;i++) t[i]=read();for(int i=1;i<=n;i++) du[i]=2;for(int i=1;i<=n;i++){fa[i]=read();du[fa[i]]++;}for(int i=1;i<=n;i++) w[i]=t[i]/du[i];for(int i=1;i<=n;i++) v[fa[i]]+=w[i];for(int i=1;i<=n;i++){ll val=v[i]+w[fa[i]]+t[i]-w[i]*(du[i]-1);sef[i]=t[i]-w[i]*(du[i]-1);//debug("i=%d val=%lld v=%lld w=%lld du\n",i,val);add(rt[fa[i]],1,n,i,val);}for(int i=1;i<=n;i++){mn.insert(tr[rt[i]].mn);mx.insert(tr[rt[i]].mx);}for(int i=1;i<=m;i++){int op=read();if(op==1){int x=read(),y=read(),f=fa[x];fa[x]=y;//debug("erase: f:(%lld %lld) y:(%lld %lld)\n",// tr[rt[f]].mn,tr[rt[f]].mx,tr[rt[y]].mn,tr[rt[y]].mx);s.insert(y);s.insert(f);s.insert(fa[y]);s.insert(fa[f]);s.insert(fa[fa[y]]);s.insert(fa[fa[f]]);for(int now:s){mn.erase(mn.find(tr[rt[now]].mn));mx.erase(mx.find(tr[rt[now]].mx));}ll val=ask(rt[f],1,n,x,1);val-=w[f];tag(rt[f],-w[f]);upd(fa[f],-w[f]);upd(f,-sef[f]);du[f]--;w[f]=t[f]/du[f];sef[f]=t[f]-w[f]*(du[f]-1);tag(rt[f],w[f]);upd(fa[f],w[f]);upd(f,sef[f]);tag(rt[y],-w[y]);upd(fa[y],-w[y]);upd(y,-sef[y]);du[y]++;w[y]=t[y]/du[y];sef[y]=t[y]-w[y]*(du[y]-1);tag(rt[y],w[y]);upd(fa[y],w[y]);upd(y,sef[y]);upd(f,-w[x]);upd(y,w[x]);val+=w[y];add(rt[y],1,n,x,val);for(int now:s){//if(n==20000) break;mn.insert(tr[rt[now]].mn);mx.insert(tr[rt[now]].mx);} //debug("insert: f:(%lld %lld) y:(%lld %lld)\n",// tr[rt[f]].mn,tr[rt[f]].mx,tr[rt[y]].mn,tr[rt[y]].mx);}else if(op==2){int x=read();//if(n<20000)printf("%lld\n",ask(rt[fa[x]],1,n,x));}else{//if(n<20000)printf("%lld %lld\n",(*mn.begin()),(*mx.rbegin()));}//if(n>=20000) printf("i=%d tot=%d\n",i,tot);//if(i%100==0){//printf("i=%d tot=%d time=%lf calc=%d\n",i,tot,1.0*clock()/CLOCKS_PER_SEC,tim);//}//if(1.0*clock()/CLOCKS_PER_SEC>4.9){//printf("i=%d tot=%d\n",i,tot);break;//}s.clear();}return 0;
}
/**/
CF643E Bear and Destroying Subtrees
Description\text{Description}Description
给你一棵初始只有根为 111 的树。
共有 qqq 次操作。
1 x
表示加入一个以 xxx 为父亲的新点。
2 x
表示求以 xxx 为根的子树期望最深深度。
每条边都有 12\dfrac{1}{2}21 的概率断裂。
1≤q≤5×1051\leq q\leq 5\times 10^51≤q≤5×105。
Solution\text{Solution}Solution
这题很 CF…
注意到,当链很长的时候不被断开的概率是极低的。
具体的,当链长超过 606060,对答案的影响完全可以忽略不计。
(经过实测,其实只考虑到 404040 都是没问题的。
这样本题就好办多了。
但依然没有显然。
由于本来答案取 max\maxmax 的性质,设计 dpx,idp_{x,i}dpx,i 表示子树内答案小于等于 iii 的概率。
那么就有转移:
dpfa,k+1=∏12×(dpson,k+1)dp_{fa,k+1}=\prod \frac{1}{2}\times (dp_{son,k}+1)dpfa,k+1=∏21×(dpson,k+1)
每次加新点对 606060 个祖先都只会改一层的 dp,所以直接暴力修改即可。
#include<bits/stdc++.h>
using namespace std;
#define ull unsigned long long
#define debug(...) fprintf(stderr,__VA_ARGS__)
const int N=5e5+100;
#define ll long long
inline ll read(){ll x(0),f(1);char c=getchar();while(!isdigit(c)){if(c=='-')f=-1;c=getchar();}while(isdigit(c)) {x=(x<<1)+(x<<3)+c-'0';c=getchar();}return x*f;
}int n,m,tim;
double dp[N][62];
int fa[N],tot=1,o=60;
void remove(int x,int k){if(!fa[x]||k>=o||!x) return;remove(fa[x],k+1);dp[fa[x]][k+1]/=(0.5*(dp[x][k]+1));return;
}
void upd(int x,int k){if(!fa[x]||k>=o||!x) return;dp[fa[x]][k+1]*=0.5*(dp[x][k]+1);//printf("fa=%d *=%lf\n",fa[x],0.5*(dp[x][k]+1));upd(fa[x],k+1);
}
signed main(){
#ifndef ONLINE_JUDGEfreopen("a.in","r",stdin);freopen("a.out","w",stdout);
#endifn=read();for(int i=1;i<=o;i++) dp[1][i]=1;for(int i=1;i<=n;i++){int op=read(),x=read();if(op==1){fa[++tot]=x;x=tot;for(int j=1;j<=o;j++) dp[x][j]=1;remove(fa[x],1);upd(x,0);}else{double ans=o-1;for(int i=1;i<o;i++) ans-=dp[x][i];printf("%.10lf\n",ans);}}return 0;
}
/**/
CF643F Bears and Juice
Description\text{Description}Description
有 nnn 只熊和若干桶果汁和恰好一桶酒,每一天每只熊会选择一些桶(可能不选)并各喝一 杯,喝到酒的熊会去睡觉并不再回来,通过这个信息,熊们想知道哪个桶里是酒。
只有 ppp 个睡 觉的位置,当睡觉的熊超过了 ppp 只或者所有熊都在睡觉时熊们就失败了。
令 RiR_iRi 表示在 iii 天内桶的数量最多少,使得熊可以成功知道酒的位置。令 Xi=(i×Ri)mod232X_i = (i\times R_i) \bmod 2^{32}Xi=(i×Ri)mod232,你需要求出 X1⊕X2⊕…⊕XqX_1 \oplus X_2 \oplus\ldots \oplus X_qX1⊕X2⊕…⊕Xq。
1≤n≤1091\leq n\leq 10^91≤n≤109,1≤p≤1301\leq p\leq 1301≤p≤130,1≤q≤2×1061\leq q \leq 2\times 10^61≤q≤2×106。
Solution\text{Solution}Solution
魔法操作。
考虑答案的上界,就是所有熊的反应的不同方案数
对于 iii 天,这个数量就是:
fi=∑j=0min(n−1,p)Cnj×ijf_i=\sum_{j=0}^{\min(n-1,p)} C_n^j\times i^jfi=j=0∑min(n−1,p)Cnj×ij
jjj 枚举喝醉的熊的数量,CnjC_n^jCnj 是从 nnn 头里选 jjj 头,每头可以从 iii 天中选一天喝醉。
然后可以发现,这个上界是可以构造出方案卡到的。
所以答案就是这个。
实现上,由于 nnn 过大,不便求 CnjC_n^jCnj,可以暴力约分来做。
Code\text{Code}Code
#include<bits/stdc++.h>
using namespace std;
#define ull unsigned long long
#define debug(...) fprintf(stderr,__VA_ARGS__)
const int N=5e5+100;
#define ll long long
#define ui unsigned int
inline ll read(){ll x(0),f(1);char c=getchar();while(!isdigit(c)){if(c=='-')f=-1;c=getchar();}while(isdigit(c)) {x=(x<<1)+(x<<3)+c-'0';c=getchar();}return x*f;
}int n,p,q;
ui a[150],b[150];
ui c[150];
ui gcd(ui a,ui b){return b?gcd(b,a%b):a;}
void init(){for(int i=0;i<=min(p,n-1);i++){for(int j=1;j<=i;j++) a[j]=j,b[j]=n-j+1;for(int j=1;j<=i;j++){for(int k=1;k<=i;k++){int g=gcd(a[j],b[k]);a[j]/=g;b[k]/=g;}assert(a[j]==1);}c[i]=1;for(int j=1;j<=i;j++) c[i]*=b[j];}return;
}
inline ui ksm(ui x,ui k){ui res(1);while(k){if(k&1) res*=x;x=x*x;k>>=1;}return res;
}
signed main(){
#ifndef ONLINE_JUDGEfreopen("a.in","r",stdin);freopen("a.out","w",stdout);
#endifn=read();p=read();q=read();init();ui ans(0);for(int i=1;i<=q;i++){ui base(1),res(0);for(int j=0;j<=min(n-1,p);j++){res+=c[j]*base;base*=i;}ans^=(i*res);}printf("%u\n",ans);return 0;
}
/**/
CF643G Choosing Ads
Description\text{Description}Description
给定一个长度为 nnn 的序列和一个整数 ppp。
- 有 mmm 个操作,操作要么是区间赋值,要么是询问区间内出现次数至少占 p%p\%p% 的数。
- 输出询问的答案时,可以包含错的数,也可以重复输出,但对的数一定要在答案中,且输出的数的个数不超过 ⌊100p⌋\lfloor \dfrac{100}{p} \rfloor⌊p100⌋。
- n,m≤1.5×105n,m \le 1.5 \times 10^5n,m≤1.5×105,20≤p≤10020 \le p \le 10020≤p≤100。
Solution\text{Solution}Solution
魔法操作。
考虑 p>50p>50p>50 (严格众数)时如何做。
每次删去两个不同的数,直到删到剩下的种类不超过一种时,如果有严格众数,显然会剩到最后。
类似的,推广到 p≥20p\ge 20p≥20 的情况。令 k=⌊100p⌋k=\lfloor \dfrac{100}{p}\rfloork=⌊p100⌋,每次删去 k+1k+1k+1 个不同的数,直到不能删为止,也易证如果有符合条件的数最后一定会剩下。
现在要对于区间询问快速模拟这个过程,使用线段树即可,每次暴力 O(k2)O(k^2)O(k2) 暴力合并区间,具体实现建议观看代码。
Code\text{Code}Code
#include<bits/stdc++.h>
using namespace std;
#define ull unsigned long long
#define debug(...) fprintf(stderr,__VA_ARGS__)
const int N=2e5+100;
#define ll long long
#define ui unsigned int
inline ll read(){ll x(0),f(1);char c=getchar();while(!isdigit(c)){if(c=='-')f=-1;c=getchar();}while(isdigit(c)) {x=(x<<1)+(x<<3)+c-'0';c=getchar();}return x*f;
}int n,k,m;struct node{int val[6],num[6],tot;
}tr[N<<2];
node operator + (const node &a,const node &b){node res=a;for(int i=1;i<=b.tot;i++){bool jd(0);for(int j=1;j<=res.tot;j++){if(res.val[j]==b.val[i]){jd=1;res.num[j]+=b.num[i];break;}}if(jd) continue;if(res.tot<k){++res.tot;res.val[res.tot]=b.val[i];res.num[res.tot]=b.num[i];continue;}int pl(1);for(int j=2;j<=res.tot;j++){if(res.num[j]<res.num[pl]) pl=j;}if(res.num[pl]>b.num[i]){for(int j=1;j<=res.tot;j++) res.num[j]-=b.num[i];}else{int o=res.num[pl];res.num[pl]=b.num[i];res.val[pl]=b.val[i];for(int j=1;j<=res.tot;j++) res.num[j]-=o;}}return res;
}#define mid ((l+r)>>1)
#define ls (k<<1)
#define rs (k<<1|1)
int laz[N<<2];
inline void pushup(int k){tr[k]=tr[ls]+tr[rs];}
inline void tag(int k,int l,int r,int v){laz[k]=v;tr[k].tot=1;tr[k].num[1]=r-l+1;tr[k].val[1]=v;return;
}
inline void pushdown(int k,int l,int r){int o=laz[k];laz[k]=0;if(!o) return;tag(ls,l,mid,o);tag(rs,mid+1,r,o);return;
}
inline void change(int k,int l,int r,int x,int y,int v){if(x<=l&&r<=y){tag(k,l,r,v);return;}pushdown(k,l,r);if(x<=mid) change(ls,l,mid,x,y,v);if(y>mid) change(rs,mid+1,r,x,y,v);pushup(k);
}
node ask(int k,int l,int r,int x,int y){ if(x<=l&&r<=y) return tr[k];pushdown(k,l,r);if(y<=mid) return ask(ls,l,mid,x,y);else if(x>mid) return ask(rs,mid+1,r,x,y);else{node a=ask(ls,l,mid,x,y),b=ask(rs,mid+1,r,x,y);return a+b;}
}
int a[N];
void build(int k,int l,int r){if(l==r){tr[k].tot=1;tr[k].num[1]=1;tr[k].val[1]=a[l];return;}build(ls,l,mid);build(rs,mid+1,r);pushup(k);
}signed main(){
#ifndef ONLINE_JUDGEfreopen("a.in","r",stdin);freopen("a.out","w",stdout);
#endifn=read();m=read();k=100/read();for(int i=1;i<=n;i++) a[i]=read();build(1,1,n);for(int i=1;i<=m;i++){int op=read(),l=read(),r=read();if(op==1){int x=read();change(1,1,n,l,r,x);}else{node res=ask(1,1,n,l,r);printf("%d ",res.tot);for(int j=1;j<=res.tot;j++) printf("%d ",res.val[j]);putchar('\n');}}return 0;
}
/*
*/