「hihoCoder1869」Items
problem
官方题解
Solutions
很妙的一个做法
首先很容易想到O(nm)的01背包,显然不能满足要求
每次加入一个数a时,我们都会用会用区间[0,m−1−a]更新[a,m−1],用[m−a,m−1]更新[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; }
|