Sort the Strings Revision
题目描述:
有n+1个长度为n的字符串---- , ,…, 。 字符串中的字符从0到n-1(从左到右)编号。字符 是 模10的数字。例如,如果n=5,则S为“01234”,如果n=14,则S为“ 01234567890123”。给定一个0到n-1的排列: , ,…, 和长度为n的数字序列: , ,…, 。 可以通过用数字 代替 的字符 来获得。 请注意,如果 与 的字符 相同,则S将与 相同.现在我们要对这n+1个字符串进行排序。 当且仅当 在字典上小于 或 等于 并且 < 时,才应将索引为i的字符串放在索引为j的字符串的左侧。让 为字符串 从左开始的新位置, 也就是说, 是排序后从左起第 个字符串。(位置是从0开始的数字)例如,如果n=5,p=[4,3,0,1,2]和d=[5,0,0,0,0],则 =“ 01234”, =“01235”, =“01205”, =“01205”, =“00205”, =“00005”。因此 =4, =5, =2, =3, =1和 =0。请求出从0到n的所有的
输入描述:
第一行包含一个整数t(1≤t≤10^ 3)表示测试用例的数量。每个测试的第一行包含一个正整数n(1≤n≤2×10^ 6)。每个测试的第二行包含四个整数
,
,
,
(0≤
,
,
<
≤10^ 9+7)。 使用以下伪代码生成p。
=
{
}
每个测试的第三行包含四个整数
,
,
,
(0
,
,
<
10^9+7)。 使用以下伪代码生成d。
测试用例中n的总和不超过10 ^ 7
输出描述:
对于每个测试,您不需要输出
的整个序列。 相反,您应该输出一个非负整数
(
样例输入:
2
5
1 3 1 4
5 2 0 170
1
0 0 0 1
1000000000 1000000006 1000000006 1000000007
样例输出:
26717147
10000019
思路:
二分+笛卡尔树 数据卡ST表T了好几遍emmmm…
通过观察
的最小值可以发现,每次可以通过
的最小值来将数列划分为两部分,在
~
之间和
~
之间重复上述过程,在
>
时字典序变大…这不就是二分吗?
所以这道题可以用二分来解:每次找到最小的
,将数列分成两部分,再继续递归,直到只有一个为止,最后比较
和
的大小。
那么问题来了,如何才能快速求出区间内
的最小值呐?这就需要引进一个知识——笛卡尔树(ST表会T)
笛卡尔树的原理大概是这样的:
用单调栈来维护一个链表,如果违背单调栈,那就放在左子树上(这里就不详细讲了,如有需要请看这里)
AC Code:
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int HASH=1e7+19;
const int MAXN=2e6+5;
const ll MAX=INT_MAX+1e8;
const ll mod=1e9+7;
ll Pseed,Pa,Pb,Pmod,P[MAXN],Dseed,Da,Db,Dmod,D[MAXN];
ll st[MAXN],ans,Rank[MAXN],has,l[MAXN],r[MAXN];
int t,n,val;
void cartesian()
{
int tmp=0,x;
for(int i=0;i<n;i++)
{
x=tmp;
while(x>0&&P[st[x]]>P[i]) x--;
if(x) r[st[x]]=i;
if(x<tmp) l[i]=st[x+1];
st[++x]=i;
tmp=x;
}
}//笛卡尔树
void dfs(int left,int right,int minn)
{
if(left>right) return;
if(left==right){Rank[left]=val++;return;}
if(P[minn]==MAX)
{
for(int i=left;i<=right;i++)
Rank[i]=val++;
return;
}
if(P[minn]%10>D[minn]) dfs(minn+1,right,r[minn]),dfs(left,minn,l[minn]);
else dfs(left,minn,l[minn]),dfs(minn+1,right,r[minn]);
}//二分
int main()
{
scanf("%d",&t);
while(t--)
{
has=1;
val=0;
ans=0;
scanf("%d",&n);
scanf("%lld%lld%lld%lld",&Pseed,&Pa,&Pb,&Pmod);
scanf("%lld%lld%lld%lld",&Dseed,&Da,&Db,&Dmod);
for(int i=0;i<n;i++)
{
P[i]=i;
D[i]=Dseed%10;
Dseed=(Dseed*Da+Db)%Dmod;
}
for(int i=1;i<n;i++)
{
swap(P[i],P[Pseed%(i+1)]);
Pseed=(Pseed*Pa+Pb)%Pmod;
}
for(int i=0;i<n;i++)
if(P[i]%10==D[i]) P[i]=MAX;//无用数据
cartesian();
dfs(0,n,st[1]);
for(int i=0;i<=n;i++)
{
ans+=(ll)(Rank[i]*has)%mod;
ans%=mod;
has*=HASH;
has%=mod;
}
printf("%lld\n",ans%mod);
}
}