A
考虑到
10
≈
log
2
1000
10 \approx \log_2 1000
10≈log21000,每个页面向外连出两条边,要求任意两点距离不超过
10
10
10,因此建一颗类似于线段树的图。点
p
p
p 连向模意义下的点
2
p
2p
2p 和
2
p
+
1
2p+1
2p+1 即可。
时间复杂度
O
(
n
)
O(n)
O(n),空间复杂度
O
(
1
)
O(1)
O(1)
#include<iostream>
using namespace std;
int main(){
int n,a,b;
cin>>n;
for(register int i=0;i!=n;i++){
a=i<<1;
b=a|1;
if(a>n){
a-=n;
}else if(a==0){
a=n;
}
if(b>n){
b-=n;
}
cout<<a<<' '<<b<<endl;
}
return 0;
}
B
先找规律,看若某些格子上有硬币的情况是否有可能。
设共有
k
k
k 个位置有硬币,第
i
i
i 枚硬币在位置
p
i
p_i
pi,
S
(
l
,
r
)
S(l,r)
S(l,r) 表示第
l
l
l 至第
r
r
r 枚硬币的集合。则
S
(
1
,
k
)
S(1,k)
S(1,k) 可行的条件为存在三个正整数
a
,
b
,
c
a,b,c
a,b,c 满足:
a
<
b
<
c
⩽
k
a<b<c \leqslant k
a<b<c⩽k
(
b
−
a
)
m
o
d
3
=
(
c
−
b
)
m
o
d
3
(b-a)\mod 3 =(c-b) \mod 3
(b−a)mod3=(c−b)mod3
a
=
1
a=1
a=1 或
S
(
1
,
a
−
1
)
S(1,a-1)
S(1,a−1) 可行
a
=
b
−
1
a=b-1
a=b−1 或
S
(
a
+
1
,
b
−
1
)
S(a+1,b-1)
S(a+1,b−1) 可行
b
=
c
−
1
b=c-1
b=c−1 或
S
(
b
+
1
,
c
−
1
)
S(b+1,c-1)
S(b+1,c−1) 可行
c
=
k
c=k
c=k 或
S
(
c
+
1
,
k
)
S(c+1,k)
S(c+1,k) 可行
因此考虑区间DP。设
f
i
,
j
f_{i,j}
fi,j 表示从位置
i
i
i 至位置
j
j
j 选一些位置放硬币的最大得分,且放置硬币的方案在该区间中可行。则DP转移为:
从区间
i
,
j
i,j
i,j 与区间
j
+
1
,
k
j+1,k
j+1,k 转移到区间
i
,
k
i,k
i,k。
若
j
−
i
m
o
d
3
=
2
j-i \mod 3 =2
j−imod3=2,则从区间中选取
k
k
k 使得
k
−
i
m
o
d
3
=
1
k-i \mod 3 =1
k−imod3=1,并从区间
i
+
1
,
k
−
1
i+1,k-1
i+1,k−1 与区间
k
+
1
,
j
−
1
k+1,j-1
k+1,j−1 转移到区间
i
,
j
i,j
i,j。
不难发现这样转移是完备的。
时间复杂度
O
(
n
3
)
O(n^3)
O(n3),空间复杂度
O
(
n
2
)
O(n^2)
O(n2)
#include<iostream>
using namespace std;
#define R register int
int f[500][500],a[500];
inline void Max(int&x,int y){
x=x>y?x:y;
}
int main(){
int n;
cin>>n;
for(R i=0;i!=n;i++){
cin>>a[i];
}
for(R i=2;i!=n;i++){
for(R j=0;i+j!=n;j++){
for(R k=i+j;k!=j;k--){
Max(f[j][i+j],f[j][k-1]+f[k][i+j]);
}
if(i%3==2){
for(R k=j+1;k<i+j;k+=3){
Max(f[j][i+j],f[j+1][k-1]+f[k+1][i+j-1]+a[j]+a[k]+a[i+j]);
}
}
}
}
cout<<f[0][n-1];
return 0;
}
C
若现有一确定的操作字符串,判断胜负情况。将字符串分为若干段,每一段S
后都会有一个B
,一段S
的长度可能为
0
0
0。设状态
(
l
,
r
)
(l,r)
(l,r) 表示Snuke左侧有
l
l
l 个连续的空位,右侧有
r
r
r 个连续的空位,经过第一段S
后状态为
(
+
∞
,
+
∞
)
(+ \infin,+ \infin)
(+∞,+∞),经过第一个B
后状态变为
(
0
,
+
∞
)
(0,+ \infin)
(0,+∞)。设当前状态为
(
0
,
r
)
(0,r)
(0,r),则又经过
b
b
b 个S
和一个B
之后的状态为
(
0
,
min
(
b
,
[
r
2
]
)
)
(0,\min(b,[\frac{r}2]))
(0,min(b,[2r]))。由此归纳得若Snuke要赢则到倒数第
i
i
i 段S
长度至少是
2
i
−
2
2^{i-2}
2i−2,其中
i
>
1
i>1
i>1。
根据结论定下DP状态,设
f
i
,
j
f_{i,j}
fi,j 表示第
i
i
i 个位置可以为B
且右侧的S
为倒数第
j
j
j 段。显然
j
⩽
log
2
n
j \leqslant \log_2n
j⩽log2n。设
i
i
i 右侧第一个B
的位置为
l
l
l 且
i
+
2
j
−
2
<
l
i+2^{j-2}<l
i+2j−2<l,则
f
i
,
j
=
∑
k
=
i
+
1
l
f
k
,
j
−
1
f_{i,j}= \sum_{k=i+1}^l f_{k,j-1}
fi,j=∑k=i+1lfk,j−1,前缀和优化DP即可。设第一个B
的位置为
p
p
p,共
Q
Q
Q 个?
,则答案为
2
Q
−
∑
i
=
1
p
∑
j
=
1
f
i
,
j
2^Q-\sum_{i=1}^p \sum_{j=1} f_{i,j}
2Q−∑i=1p∑j=1fi,j。当原字符串不存在B
时特殊处理,答案为
2
Q
−
1
−
∑
i
=
1
n
∑
j
=
1
f
i
,
j
2^Q-1-\sum_{i=1}^n \sum_{j=1} f_{i,j}
2Q−1−∑i=1n∑j=1fi,j。仔细处理边界情况。
时空复杂度
O
(
n
log
2
n
)
O(n \log_2n)
O(nlog2n)
#include<iostream>
using namespace std;
#define R register int
#define P 998244353
int f[1000000][20],g[1000002][20];
inline int Add(int x,const int y){
x+=y;
return x<P?x:x-P;
}
int main(){
string s;
cin>>s;
int n=s.length(),ans=1,l,t;
bool tag=true;
l=n;
for(R i=n-1;i!=-1;i--){
if(s[i]=='?'){
ans<<=1;
if(ans>P){
ans-=P;
}
}
if(s[i]!='S'){
if(l==n){
f[i][0]=1;
}
for(R j=0;j!=19;j++){
t=i+(1<<j);
if(t<l){
f[i][j+1]=Add(g[t+1][j],P-g[l+1][j]);
}
}
}
if(s[i]=='B'){
l=i;
tag=false;
}
for(R j=0;j!=20;j++){
g[i][j]=Add(f[i][j],g[i+1][j]);
}
}
if(tag==true){
ans--;
}
for(R i=0;i<=l;i++){
for(R j=0;j!=20;j++){
ans=Add(ans,P-f[i][j]);
}
}
cout<<ans;
return 0;
}
D
考虑影响答案的因素。比较显然的有执行的轮数,剩余人数,当前操作的人以及正在计算的人在人群中的排名。设
f
p
r
e
,
s
u
f
,
r
,
p
o
s
f_{pre,suf,r,pos}
fpre,suf,r,pos 表示编号比当前正在计算的人编号小的有
p
r
e
pre
pre 人,编号大的有
s
u
f
suf
suf 人,正在执行了
r
r
r 轮,当前操作的人在人群中编号排名为
p
o
s
pos
pos。由于剩下的人抽中新的物品的概率
p
p
p 一定为
p
r
e
+
s
u
f
+
1
+
k
−
n
k
−
r
\frac{pre+suf+1+k-n}{k-r}
k−rpre+suf+1+k−n,DP转移考虑每种情况对参数的影响即可。
时空复杂度
O
(
n
4
)
O(n^4)
O(n4)
#include<iostream>
using namespace std;
#define R register int
#define L long long
#define P 998244353
inline int Add(int x,const int y){
x+=y;
return x<P?x:x-P;
}
int f[40][40][41][41],inv[41];
inline int GetAns(int pre,int suf,int r,int pos,int&n,int&k){
int&g=f[pre][suf][r][pos];
if(g!=-1){
return g;
}
g=0;
int tot=pre+suf+1,p,q;
if(r==k||n-tot==k){
return 0;
}
p=(L)(tot+k-n)*inv[k-r]%P;
q=Add(P-p,1);
if(pre+1==pos){
g=((L)q*GetAns(pre,suf,r+(suf==0),suf==0?1:pos+1,n,k)+p)%P;
}else if(pos>pre){
g=((L)p*GetAns(pre,suf-1,r+(pos==tot),(pos-1)%(tot-1)+1,n,k)+(L)q*GetAns(pre,suf,r+(pos==tot),pos%tot+1,n,k))%P;
}else{
g=((L)p*GetAns(pre-1,suf,r,pos,n,k)+(L)q*GetAns(pre,suf,r,pos+1,n,k))%P;
}
return g;
}
int main(){
putchar('1');
inv[1]=1;
int n,p;
cin>>n>>p;
for(R i=2;i<=p;i++){
inv[i]=(L)(P-P/i)*inv[P%i]%P;
}
for(R i=0;i!=n;i++){
for(R j=0;j!=n;j++){
for(R k=0;k<=n;k++){
for(R l=0;l<=n;l++){
f[i][j][k][l]=-1;
}
}
}
}
for(R i=2;i<=n;i++){
printf("\n%d",GetAns(i-1,n-i,0,1,n,p));
}
return 0;
}
E
设
(
a
,
b
,
c
,
d
,
e
,
f
)
(a,b,c,d,e,f)
(a,b,c,d,e,f) 表示是否存在自然数
x
x
x 使得
x
m
o
d
b
=
a
x \mod b=a
xmodb=a 且
x
m
o
d
d
=
c
x \mod d =c
xmodd=c 且
x
m
o
d
f
=
e
x \mod f=e
xmodf=e。设
m
i
=
g
i
+
r
i
m_i=g_i+r_i
mi=gi+ri,则答案为
∑
i
=
0
g
1
−
1
∑
j
=
0
g
2
−
1
∑
k
=
0
g
3
−
1
(
i
,
m
1
,
j
,
m
2
,
k
,
m
3
)
\sum_{i=0}^{g_1-1} \sum_{j=0}^{g_2-1} \sum_{k=0}^{g_3-1}(i,m_1,j,m_2,k,m_3)
∑i=0g1−1∑j=0g2−1∑k=0g3−1(i,m1,j,m2,k,m3)。若存在素数
p
p
p 使得
p
∣
b
p \mid b
p∣b 且
p
∤
d
,
f
p \nmid d,f
p∤d,f,则
(
a
,
b
,
c
,
d
,
e
,
f
)
=
(
a
m
o
d
(
b
p
)
,
b
p
,
c
,
d
,
e
,
f
)
(a,b,c,d,e,f)=(a \mod(\frac{b}{p}),\frac{b}p,c,d,e,f)
(a,b,c,d,e,f)=(amod(pb),pb,c,d,e,f)。将此结论推广,若
p
t
1
∥
b
,
p
t
2
∥
d
,
p
t
3
∥
f
p^{t_1} \parallel b,p^{t_2} \parallel d,p^{t_3} \parallel f
pt1∥b,pt2∥d,pt3∥f,且
max
(
t
1
,
t
2
)
⩽
t
3
\max(t_1,t_2) \leqslant t_3
max(t1,t2)⩽t3,设
f
′
=
p
max
(
t
1
,
t
2
)
−
t
3
f
f'=p^{\max(t_1,t_2)-t_3}f
f′=pmax(t1,t2)−t3f,则
(
a
,
b
,
c
,
d
,
e
,
f
)
=
(
a
,
b
,
c
,
d
,
e
m
o
d
f
′
,
f
′
)
(a,b,c,d,e,f)=(a,b,c,d,e \mod f',f')
(a,b,c,d,e,f)=(a,b,c,d,emodf′,f′)。经过变换,可以使得
m
1
∣
m
2
m
3
,
m
2
∣
m
1
m
3
,
m
3
∣
m
1
m
2
m_1 \mid m_2 m_3,m_2 \mid m_1 m_3,m_3 \mid m_1 m_2
m1∣m2m3,m2∣m1m3,m3∣m1m2。
设
g
=
gcd
(
m
1
,
m
2
,
m
3
)
,
m
1
=
g
a
b
,
m
2
=
g
a
c
,
m
3
=
g
b
c
,
a
⩽
b
⩽
c
g=\gcd(m_1,m_2,m_3),m_1=gab,m_2=gac,m_3=gbc,a \leqslant b \leqslant c
g=gcd(m1,m2,m3),m1=gab,m2=gac,m3=gbc,a⩽b⩽c。暴力模拟
2
,
3
2,3
2,3号信号灯的颜色变化,时间复杂度
O
(
a
+
b
)
O(a+b)
O(a+b)。由于
a
⩽
b
⩽
b
c
⩽
c
,
b
c
⩽
g
b
c
=
m
3
a \leqslant b \leqslant \sqrt{bc} \leqslant c,bc \leqslant gbc=m_3
a⩽b⩽bc⩽c,bc⩽gbc=m3。因此
a
⩽
b
⩽
m
3
a \leqslant b \leqslant \sqrt{m_3}
a⩽b⩽m3。
时间复杂度
O
(
g
+
r
)
O(\sqrt{g+r})
O(g+r),空间复杂度
O
(
1
)
O(1)
O(1)
#include<iostream>
using namespace std;
#define R register int
#define L long long
#define I inline
#define P 998244353
I void Swap(L&x,L&y){
L tem=x;
x=y;
y=tem;
}
I L Min(L x,L y){
return x<y?x:y;
}
I void Compare(L&g1,L&m1,L&g2,L&m2){
if(m1<m2){
Swap(g1,g2);
Swap(m1,m2);
}
}
I L Gcd(L x,L y){
return y==0?x:Gcd(y,x%y);
}
I L Calc(L m1,L m2,L m3){
L v=m1/Gcd(m1,m2);
v/=Gcd(v,m3);
return m1/v;
}
I int Calc2(L l1,L r1,L l2,L r2,L g3,L m3){
L l=l1>l2?l1:l2,r=Min(r1,r2);
if(l>r){
return 0;
}
int res=(r/m3%P*(g3+1)+Min(r%m3,g3)-(l-1)/m3%P*(g3+1)-Min((l-1)%m3,g3))%P;
return res<0?res+P:res;
}
I int Solve(L g1,L m1,L g2,L m2,L g3,L m3){
L v=Calc(m1,m2,m3);
if(v!=m1){
return(g1/v%P*Solve(v-1,v,g2,m2,g3,m3)+Solve(g1%v,v,g2,m2,g3,m3))%P;
}
v=Calc(m2,m1,m3);
if(v!=m2){
return(g2/v%P*Solve(g1,m1,v-1,v,g3,m3)+Solve(g1,m1,g2%v,v,g3,m3))%P;
}
v=Calc(m3,m1,m2);
if(v!=m3){
return(g3/v%P*Solve(g1,m1,g2,m2,v-1,v)+Solve(g1,m1,g2,m2,g3%v,v))%P;
}
Compare(g1,m1,g2,m2);
Compare(g1,m1,g3,m3);
Compare(g2,m2,g3,m3);
L l1=0,l2=0,r1=g1,r2=g2;
int res=0;
while(l1!=l2||l1%m3!=0||l1==0){
res+=Calc2(l1,r1,l2,r2,g3,m3);
if(res>=P){
res-=P;
}
if(r1<r2){
l1+=m1;
r1+=m1;
}else{
l2+=m2;
r2+=m2;
}
}
v=Gcd(m1,l1);
m1/=v;
l1/=v;
v=Gcd(m2,l1);
m2/=v;
l1/=v;
v=Gcd(m3,l1);
m3/=v;
l1/=v;
return m1%P*(m2%P)%P*(m3%P)%P*res%P;
}
int main(){
L g1,r1,g2,r2,g3,r3;
cin>>g1>>r1>>g2>>r2>>g3>>r3;
printf("%d",Solve(g1-1,g1+r1,g2-1,g2+r2,g3-1,g3+r3));
return 0;
}