Date:2022.03.12
题目描述:
小沙的人生充满坎坷,他现在准备remake,在新的人生中他想要自己的人生一帆风顺,步步高升,所以他希望自己的气运不会下降,他的新的人生,活的时间可以不长,但一定要步步高升。
现在有
n
n
n个气运放在小沙面前,小沙只能按着顺序选择,对于一个气运,他只能选择选或不选,并且他希望这个气运不能比之前已经选择的低,现在小沙想问你,小沙生成的新的人生有多少种可能。
对于每个气运来说,每个气运都有自己的依赖性,他希望选择的气运的前
b
i
b_i
bi 个以内至少存在一个已被选择的气运(也就是下标为
[
i
−
b
,
i
)
[i-b,i)
[i−b,i),要是超出了这个范围,他们就不愿意被你选择,从而自主消失,当然,如果你第一个选择他,他也是愿意被你选择的。
对于每个气运,小沙如果不选就会消失,并不能之后在回头来选。
对于小沙选择的气运序列,只要有一个不同,他就是一种新的人生。
由于答案比较大,所以小沙希望你对1e9+7取模。
对于C/C++语言
#include<bits/stdc++.h> namespace GenHelper {
int z1,z2,z3,z4,z5,u,res;
int get()
{
z5=((z1<<6)^z1)>>13;
z1=((int)(z1&4294967)<<18)^z5;
z5=((z2<<2)^z2)>>27;
z2=((z2&4294968)<<2)^z5;
z5=((z3<<13)^z3)>>21;
z3=((z3&4294967)<<7)^z5;
z5=((z4<<3)^z4)>>12;
z4=((z4&4294967)<<13)^z5;
return (z1z2z3^z4);
}
int read(int m) {
u=get();
u>>=1;
if(m==0)res=u;
else res=(u/2345+1000054321)%m;
return res;
}
void srand(int x)
{
z1=x;
z2=(~x)^(0x23333333);
z3=x^(0x12345798);
z4=(~x)+51;
u = 0;
} } using namespace GenHelper; using namespace std; const int N=2e6+7,mod=1e9+7; int a[N],b[N]; int main(){
int n,seed;
scanf("%d %d",&n,&seed);
srand(seed);
for(int i=1;i<=n;i++){
a[i]=read(0),b[i]=read(i);
}
return 0; }JAVA版代码 import java.util.; import java.math.; public class Main{
static int z1,z2,z3,z4,z5,u,res;
public static int get(){
z5=((z1<<6)^z1)>>13;
z1=((int)(z1&4294967)<<18)^z5;
z5=((z2<<2)^z2)>>27;
z2=((z2&4294968)<<2)^z5;
z5=((z3<<13)^z3)>>21;
z3=((z3&4294967)<<7)^z5;
z5=((z4<<3)^z4)>>12;
z4=((z4&4294967)<<13)^z5;
return (z1z2z3^z4);
}
public static int read(int m){
u=get();
u>>=1;
if(m==0)res=u;
else res=(u/2345+1000054321)%m;;
return res;
}
public static void ssrand(int x){
z1=x;
z2=(~x)^(0x23333333);
z3=x^(0x12345798);
z4=(~x)+51;
u = 0;
}
public static void main(String args[]) {
Scanner in=new Scanner(System.in);
int a[]=new int[2000010];
int b[]=new int[2000010];
int n=in.nextInt(),seed=in.nextInt();
ssrand(seed);
for(int i=1;i<=n;i++){
a[i]=read(0);
b[i]=read(i);
}
} }Python代码: 不会写你们对着自己写写吧QAQ。
输入描述:
第一行输入两个整数n,seed。
1
<
=
n
<
=
2
×
1
0
6
,
0
<
=
b
i
<
i
1<=n<=2\times10^6,0<=b_i<i
1<=n<=2×106,0<=bi<i
输出描述:
输出一个数代表答案
示例1
输入
复制
3 2
输出
复制
4
说明
得到的数为
8803593 0
3293267 0
268485133 1
可以看出答案为4个
选第一个 不选第二个 不选第三个
不选第一个 选第二个 不选第三个
不选第一个 选第二个 选第三个
不选第一个 不选第二个 选第三个
错误示范:
选第一个 不选第二个 选第三个
虽然第三个比第一个大,但是没有选择第二个,并且第三个不是第一个选择,所以不能选择第三个
思路:看样子是dp,首先搞清楚一个点(下标为
i
i
i)会被选择的两种情况:
①这是被选的第1个点。(显然这就是一种方案。)
②其前面
[
i
−
b
i
,
i
)
[i-b_i,i)
[i−bi,i)区间中已被选择了若干个点,并且后被选的点权值一定
>
=
>=
>=先被选的点。
这就给了我们一个排序的思路:
①标记每个点的原始下标。
②按每个点的值为第一要素排序。
状态方程:
f
[
i
]
:
f[i]:
f[i]:以原始下标
i
i
i为最后一个选择的人生有多少种方案。
由此保证:权值上
前
<
=
后
前<=后
前<=后。如果能保证下标也是
前
<
后
前<后
前<后,那么问题可以转化为
f
[
i
]
=
f
[
i
−
b
i
−
1
]
+
.
.
.
+
f
[
i
−
1
]
f[i]=f[i-b_i-1]+...+f[i-1]
f[i]=f[i−bi−1]+...+f[i−1],即区间求和,因此既能满足使下标递增也能快速区间求和显然用BIT优化!每次快速求和后赋值给新的
f
[
i
]
f[i]
f[i],最终结果即为
g
e
t
s
u
m
(
n
)
=
=
f
[
1
]
+
f
[
2
]
.
.
.
+
f
[
n
]
getsum(n)==f[1]+f[2]...+f[n]
getsum(n)==f[1]+f[2]...+f[n]。
代码如下:
#include<bits/stdc++.h>
#define x first
#define y second
namespace GenHelper
{
int z1,z2,z3,z4,z5,u,res;
int get()
{
z5=((z1<<6)^z1)>>13;
z1=((int)(z1&4294967)<<18)^z5;
z5=((z2<<2)^z2)>>27;
z2=((z2&4294968)<<2)^z5;
z5=((z3<<13)^z3)>>21;
z3=((z3&4294967)<<7)^z5;
z5=((z4<<3)^z4)>>12;
z4=((z4&4294967)<<13)^z5;
return (z1^z2^z3^z4);
}
int read(int m) {
u=get();
u>>=1;
if(m==0)res=u;
else res=(u/2345+1000054321)%m;
return res;
}
void srand(int x)
{
z1=x;
z2=(~x)^(0x23333333);
z3=x^(0x12345798);
z4=(~x)+51;
u = 0;
}
}
using namespace GenHelper;
using namespace std;
const int N=2e6+7,mod=1e9+7;
typedef long long LL;
typedef pair<int,int> PII;
int a[N],b[N],n,seed;
LL tr[N];//dp的状态方程,表示:
PII s[N];
int lowbit(int x) {return x&-x;}
void add(LL x,LL c)
{
for(int i=x;i<=n;i+=lowbit(i)) tr[i]=(tr[i]+c)%mod;
}
LL getsum(LL x)
{
LL res=0;
for(int i=x;i;i-=lowbit(i)) res=(res+tr[i])%mod;
return res;
}
int main()
{
scanf("%d %d",&n,&seed);
srand(seed);
for(int i=1;i<=n;++i)
{
a[i]=read(0),b[i]=read(i);
s[i].x=a[i];s[i].y=i;
}
sort(s+1,s+1+n);
for(int i=1;i<=n;++i)
{
LL k=((getsum(s[i].y-1)-getsum(s[i].y-b[s[i].y]-1))%mod+1+mod)%mod;//[i-bi,i)与第一个选i的方案和。
add(s[i].y,k);//赋给当前原坐标,是一个dp的过程
}
printf("%lld",getsum(n));
return 0;
}