用户工具

站点工具


2020-2021:teams:legal_string:jxm2001:笛卡尔树

差别

这里会显示出您选择的修订版和当前版本之间的差别。

到此差别页面的链接

两侧同时换到之前的修订记录 前一修订版
后一修订版
前一修订版
2020-2021:teams:legal_string:jxm2001:笛卡尔树 [2020/07/24 23:11]
jxm2001
2020-2021:teams:legal_string:jxm2001:笛卡尔树 [2020/07/27 22:56] (当前版本)
jxm2001 ↷ 页面2020-2021:teams:legal_string:笛卡尔树被移动至2020-2021:teams:legal_string:jxm2001:笛卡尔树
行 81: 行 81:
 <hidden 查看代码>​ <hidden 查看代码>​
 <code cpp> <code cpp>
-#include <​iostream>​ 
-#include <​cstdio>​ 
-#include <​cstdlib>​ 
-#include <​algorithm>​ 
-#include <​string>​ 
-#include <​sstream>​ 
-#include <​cstring>​ 
-#include <​cctype>​ 
-#include <​cmath>​ 
-#include <​vector>​ 
-#include <set> 
-#include <map> 
-#include <​stack>​ 
-#include <​queue>​ 
-#include <​ctime>​ 
-#include <​cassert>​ 
-#define _for(i,a,b) for(int i=(a);​i<​(b);​++i) 
-#define _rep(i,a,b) for(int i=(a);​i<​=(b);​++i) 
-#define mem(a,b) memset(a,​b,​sizeof(a)) 
-using namespace std; 
-typedef long long LL; 
-inline int read_int(){ 
- int t=0;bool sign=false;​char c=getchar();​ 
- while(!isdigit(c)){sign|=c=='​-';​c=getchar();​} 
- while(isdigit(c)){t=(t<<​1)+(t<<​3)+(c&​15);​c=getchar();​} 
- return sign?-t:t; 
-} 
-inline LL read_LL(){ 
- LL t=0;bool sign=false;​char c=getchar();​ 
- while(!isdigit(c)){sign|=c=='​-';​c=getchar();​} 
- while(isdigit(c)){t=(t<<​1)+(t<<​3)+(c&​15);​c=getchar();​} 
- return sign?-t:t; 
-} 
-inline char get_char(){ 
- char c=getchar();​ 
- while(c=='​ '​||c=='​\n'​||c=='​\r'​)c=getchar();​ 
- return c; 
-} 
-inline void write(LL x){ 
- register char c[21],​len=0;​ 
- if(!x)return putchar('​0'​),​void();​ 
- if(x<​0)x=-x,​putchar('​-'​);​ 
- while(x)c[++len]=x%10,​x/​=10;​ 
- while(len)putchar(c[len--]+48);​ 
-} 
-inline void space(LL x){write(x),​putchar('​ ');} 
-inline void enter(LL x){write(x),​putchar('​\n'​);​} 
 const int MAXN=505,​MAXH=1e6+5,​mod=1e9+7;​ const int MAXN=505,​MAXH=1e6+5,​mod=1e9+7;​
 LL frac[MAXH],​inv[MAXH];​ LL frac[MAXH],​inv[MAXH];​
行 206: 行 159:
 <hidden 查看代码>​ <hidden 查看代码>​
 <code cpp> <code cpp>
-#include <​iostream>​ 
-#include <​cstdio>​ 
-#include <​cstdlib>​ 
-#include <​algorithm>​ 
-#include <​string>​ 
-#include <​sstream>​ 
-#include <​cstring>​ 
-#include <​cctype>​ 
-#include <​cmath>​ 
-#include <​vector>​ 
-#include <set> 
-#include <map> 
-#include <​stack>​ 
-#include <​queue>​ 
-#include <​ctime>​ 
-#include <​cassert>​ 
-#define _for(i,a,b) for(int i=(a);​i<​(b);​++i) 
-#define _rep(i,a,b) for(int i=(a);​i<​=(b);​++i) 
-#define mem(a,b) memset(a,​b,​sizeof(a)) 
-using namespace std; 
-typedef long long LL; 
-inline int read_int(){ 
- int t=0;bool sign=false;​char c=getchar();​ 
- while(!isdigit(c)){sign|=c=='​-';​c=getchar();​} 
- while(isdigit(c)){t=(t<<​1)+(t<<​3)+(c&​15);​c=getchar();​} 
- return sign?-t:t; 
-} 
-inline LL read_LL(){ 
- LL t=0;bool sign=false;​char c=getchar();​ 
- while(!isdigit(c)){sign|=c=='​-';​c=getchar();​} 
- while(isdigit(c)){t=(t<<​1)+(t<<​3)+(c&​15);​c=getchar();​} 
- return sign?-t:t; 
-} 
-inline char get_char(){ 
- char c=getchar();​ 
- while(c=='​ '​||c=='​\n'​||c=='​\r'​)c=getchar();​ 
- return c; 
-} 
-inline void write(LL x){ 
- register char c[21],​len=0;​ 
- if(!x)return putchar('​0'​),​void();​ 
- if(x<​0)x=-x,​putchar('​-'​);​ 
- while(x)c[++len]=x%10,​x/​=10;​ 
- while(len)putchar(c[len--]+48);​ 
-} 
-inline void space(LL x){write(x),​putchar('​ ');} 
-inline void enter(LL x){write(x),​putchar('​\n'​);​} 
 const int MAXN=505,​MAXH=1e6+5,​mod=1e9+7;​ const int MAXN=505,​MAXH=1e6+5,​mod=1e9+7;​
 LL frac[MAXH],​inv[MAXH];​ LL frac[MAXH],​inv[MAXH];​
行 326: 行 232:
 === 题意 === === 题意 ===
  
 +有一个长度为 $n$ 的字符串 $s_0$, 第 $i$ 个字符是数字 $i\bmod 10$。
 +
 +给定一个 $0\sim n-1$ 的排列 $p$ 和一个数值范围在 $0\sim 9$ 的数列 $d$。
 +
 +字符串 $s_i$ 是把字符串 $s_{i-1}$ 的第 $p_i$ 个字符改成 $d_i$ 的结果。
 +
 +将这 $n+1$ 个字符串按字典序排序,字典序相同时按字符串编号排序,输出每个字符串在排序后的位置(范围为 $0\sim n$)。
  
 === 题解 === === 题解 ===
 +
 +首先假设所有 $d_i\neq p_i\bmod 10$,先考虑 $p_i=1$ 的位置。
 +
 +如果有 $d_i\lt p_i\bmod 10$,则显然有 $s_0\sim s_{i-1}$ 字典序大于 $s_i\sim s_n$,考虑将 $s_0\sim s_{i-1}$ 排名加上 $n-i+1$。
 +
 +如果有 $d_i\gt p_i\bmod 10$,则显然有 $s_0\sim s_{i-1}$ 字典序小于 $s_i\sim s_n$,考虑将 $s_i\sim s_n$ 排名加上 $i$。
 +
 +接下来 $p_i=1$ 将 $s$ 分为 $s_0\sim s_{i-1},​s_i\sim s_n$ 两个区间,且两区间互不影响,可以分别递归求解。
 +
 +由于每次需要找到该区间 $p_i$ 最小的位置并划分区间,发现笛卡尔树恰好满足要求。
 +
 +排名修改可以考虑差分处理。
 +
 +最后是 $d_i=p_i\bmod 10$ 的情况,可以考虑将 $p_i$ 修改为 $\inf$,这样 $p_i$ 的影响一定会最后考虑。
 +
 +由于此时字典序相同,所以是 $s_\text{left}\sim s_{i-1}$ 字典序小于 $s_i\sim s_\text{right}$。
 +
 +该情况影响与 $d_i\gt p_i\bmod 10$ 的情况相同,考虑合并这两种情况,改为 $d_i\ge p_i\bmod 10$。 ​
 +
 +<hidden 查看代码>​
 +<code cpp>
 +const int MAXN=2e6+5,​Inf=1e9,​Base=1e7+19,​Mod=1e9+7;​
 +int n,​p[MAXN],​d[MAXN];​
 +void init(){
 + int seed=read_int(),​a=read_int(),​b=read_int(),​mod=read_int();​
 + _for(i,​0,​n)p[i]=i;​
 + _for(i,​1,​n){
 + swap(p[i],​p[seed%(i+1)]);​
 + seed=(1LL*seed*a+b)%mod;​
 + }
 + seed=read_int(),​a=read_int(),​b=read_int(),​mod=read_int();​
 + _for(i,​0,​n){
 + d[i]=seed%10;​
 + seed=(1LL*seed*a+b)%mod;​
 + }
 + for(int i=n;​i;​i--)p[i]=p[i-1],​d[i]=d[i-1];​
 +}
 +int Stack[MAXN],​ch[MAXN][2],​root;​
 +void build(int n){ 
 + int top=0;
 + p[0]=-Inf;​Stack[++top]=0;​
 + _rep(i,​1,​n){
 + while(p[i]<​p[Stack[top]])top--;​
 + ch[i][0]=ch[Stack[top]][1];​
 + ch[Stack[top]][1]=i;​
 + Stack[++top]=i;​
 + }
 + root=Stack[2];​
 +}
 +int s[MAXN];
 +void dfs(int pos,int lef,int rig){
 + if(lef>​=rig)return;​
 + if(d[pos]>​=0){
 + s[pos]+=pos-lef;​
 + s[rig+1]-=pos-lef;​
 + }
 + else{
 + s[lef]+=rig-pos+1;​
 + s[pos]-=rig-pos+1;​
 + }
 + dfs(ch[pos][0],​lef,​pos-1);​
 + dfs(ch[pos][1],​pos,​rig);​
 +}
 +int main()
 +{
 + int t=read_int();​
 + while(t--){
 + n=read_int();​
 + init();
 + s[0]=0;
 + _rep(i,​1,​n){
 + s[i]=0;
 + d[i]-=p[i]%10;​
 + if(!d[i])p[i]=Inf;​
 + }
 + build(n);
 + dfs(root,​0,​n);​
 + _rep(i,​1,​n)
 + s[i]+=s[i-1];​
 + int ans=0,​base=1;​
 + _rep(i,​0,​n){
 + ans=(ans+1LL*s[i]*base)%Mod;​
 + base=1LL*base*Base%Mod;​
 + }
 + enter(ans);​
 + }
 + return 0;
 +}
 +</​code>​
 +</​hidden>​
2020-2021/teams/legal_string/jxm2001/笛卡尔树.1595603507.txt.gz · 最后更改: 2020/07/24 23:11 由 jxm2001