「hihoCoder1869」Items

problem

官方题解

Solutions

很妙的一个做法

首先很容易想到O(nm)O(nm)的01背包,显然不能满足要求

每次加入一个数aa时,我们都会用会用区间[0,m1a][0,m-1-a]更新[a,m1][a,m-1],用[ma,m1][m-a,m-1]更新[0,a1][0,a-1]

对于上面的每一组区间而言,两个值不同的对应位置前面一定有一段相同的子串。

因此我们二分某两个对应区间的lcp的长度,可以通过哈希判定相同。然后对值不同的对应位置记录能否成功转移,再逐步向后执行相同的操作。

最后进行修改,hash可以利用树状数组来维护。

这样我们就成功地把很多不必要的操作省去从而达到降低时间复杂度的目的

具体复杂度和证明可以看官方题解

Code

不知道为什么跑得很慢,尚不清楚是否是对题解的理解产生了偏差

欢迎指正

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstdlib>
#include <cstring>
#include <cmath>
#define lowbit(t) ((t)&(-(t)))
#define inv(x) (fastpow((x),mod-2))
using namespace std;
typedef long long ll;

template <typename T> void read(T &t)
{
t=0;int f=0;char c=getchar();
while(!isdigit(c)){f|=f=='-';c=getchar();}
while(isdigit(c)){t=t*10+c-'0';c=getchar();}
if(f)t=-t;
}

const ll mod=998244353,base=3;
const int maxn=300000+5,maxm=300000+5;

int n,m,q;
ll pow3[maxm],inv3[maxm];
int dp[maxm];
struct BitTree
{
ll c[maxm];
void Add(int x,ll v)
{
for(;x<=m;x+=lowbit(x))
c[x]=(c[x]+v)%mod;
}
ll Query(int l,int r)
{
ll re=0;
--l;
for(;r;r-=lowbit(r))
re=(re+c[r])%mod;
for(;l;l-=lowbit(l))
re=(re-c[l]+mod)%mod;
return re;
}
}t;

ll fastpow(ll a,ll b)
{
ll re=1,base=a;
while(b)
{
if(b&1)
re=re*base%mod;
base=base*base%mod;
b>>=1;
}
return re;
}

void Inti()
{
pow3[m]=1,inv3[m]=1,inv3[m-1]=inv(3);
for(register int i=m-1;i;--i)
{
pow3[i]=(pow3[i+1]*3)%mod;
inv3[i]=(inv3[i+1]*inv3[m-1])%mod;
}
}

inline ll Hash(int l,int r)
{
return t.Query(l,r)*inv3[r]%mod;
}

inline bool Check(int la,int ra,int lb,int rb)
{
return Hash(la,ra)==Hash(lb,rb);
}

int BS(int l,int r,int b1,int b2)
{
int ans=0;
while(l<=r)
{
int mid=(l+r)>>1;
if(Check(b1,b1+mid-1,b2,b2+mid-1))
ans=mid,l=mid+1;
else
r=mid-1;
}
return ans;
}

int update[maxm];
int main()
{
read(n),read(m);
Inti();
dp[1]=1;
t.Add(1,pow3[1]);
for(register int i=1;i<=n;++i)
{
int a;
read(a);
int offset=0;
update[0]=0;
while(!Check(1+offset,m-a,a+1+offset,m))
{
int len=BS(1,m-a-offset,1+offset,a+1+offset);
if(dp[1+offset+len] && !dp[a+1+offset+len])
update[++update[0]]=a+1+offset+len;
offset+=len+1;
}
offset=0;
while(!Check(m-a+1+offset,m,1+offset,a))
{
int len=BS(1,a-offset,m-a+1+offset,1+offset);
if(dp[m-a+1+offset+len] && !dp[1+offset+len])
update[++update[0]]=1+offset+len;
offset+=len+1;
}
for(register int j=1;j<=update[0];++j)
{
t.Add(update[j],pow3[update[j]]);
dp[update[j]]=1;
}
}
read(q);
while(q--)
{
int x;
read(x);
printf(dp[x+1]?"YES\n":"NO\n");
}
return 0;
}