2019CCPC哈尔滨 L. LRU Algorithm(字符串)
做法1:Trie
//
// Created by Artist on 2021/10/29.
//
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
#define mkp make_pair
#define fi first
#define se second
#define pb push_back
#define all(x) x.begin(),x.end()
#define DB1(args...) do { cout << #args << " : "; dbg(args); } while (0)
#define endl '\n'
void dbg() { std::cout << " #\n"; }
template<typename T, typename...Args>
void dbg(T a, Args...args) {
std::cout << a << ' ';
dbg(args...);
}
void io() { ios::sync_with_stdio(0), cin.tie(0), cout.tie(0); }
const int maxn = 5004;
const int N = 2e6+5;
int a[maxn];
int b[maxn];
int cache[maxn],lst[maxn];
struct Trie {
unordered_map<int,int> next[N];
int vis[N];
int cnt;
void init() {
cnt=0;
next[0].clear();
}
int newnode() {
vis[++cnt]=0;
next[cnt].clear();
return cnt;
}
int insert(int len) {
int cur=0;
for(int i=1;i<=len;++i) {
if(!next[cur].count(b[i])) next[cur][b[i]]=newnode();
cur = next[cur][b[i]];
}
return cur;
}
void query(int len) {
int cur=0;
for(int i=1;i<=len;++i) {
if(!next[cur].count(cache[i])) break;
cur = next[cur][cache[i]];
vis[cur]=1;
}
while(next[cur].count(0)) {
cur = next[cur][0];
vis[cur]=1;
}
}
}trie;
signed main() {
io();
int _;cin>>_;
while(_--) {
int n,q;cin>>n>>q;
trie.init();
for(int i=1;i<=n;++i) {
cin>>a[i];
}
for(int i=1;i<=q;++i) {
int tmp;cin>>tmp;
for(int j=1;j<=tmp;++j) {
cin>>b[j];
}
lst[i] = trie.insert(tmp);
}
int cnt=0;
for(int i=1;i<=n;++i) {
int pos=-1;
for(int j=1;j<=cnt;++j) {
if(a[i]==cache[j]) {
pos=j;
break;
}
}
if(pos==-1) {
for(int j=cnt;j;--j) {
cache[j+1]=cache[j];
}
cnt++;
cache[1] = a[i];
} else {
for(int j=pos-1;j;--j) {
cache[j+1]=cache[j];
}
cache[1] = a[i];
}
trie.query(cnt);
}
for(int i=1;i<=q;++i) {
if(trie.vis[lst[i]]) {
cout<<"Yes"<<endl;
} else {
cout<<"No"<<endl;
}
}
}
}
做法2:哈希
//
// Created by Artist on 2021/10/29.
//
// 哈希版本
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
#define mkp make_pair
#define fi first
#define se second
#define pb push_back
#define all(x) x.begin(),x.end()
#define DB1(args...) do { cout << #args << " : "; dbg(args); } while (0)
#define endl '\n'
void dbg() { std::cout << " #\n"; }
template<typename T, typename...Args>
void dbg(T a, Args...args) {
std::cout << a << ' ';
dbg(args...);
}
void io() { ios::sync_with_stdio(0), cin.tie(0), cout.tie(0); }
const int maxn = 5e3+3;
const int maxq = 2e3+3;
//const int N = 2e6+4;
int a[maxn];
vector<int> query[maxq];
int cache[maxn],len[maxn];
typedef unsigned long long ull;
ull seed=31,base[maxn],_hash[maxn],value[maxq];
void init() {
base[0]=1;
for(int i=1;i<maxn;++i)
base[i]=base[i-1]*seed;
}
ull gethash(int i,int l) {
return _hash[i+l-1]-_hash[i-1]*base[l];
}
int vis[maxq];
signed main() {
io();
int t;cin>>t;
init();
while(t--) {
int n,q;cin>>n>>q;
for(int i=1;i<=q;++i) {
query[i].clear();
vis[i]=0;
value[i]=0;
}
for(int i=1;i<=n;++i) {
cin>>a[i];
}
for(int i=1;i<=q;++i) {
cin>>len[i];
for(int j=1;j<=len[i];++j) {
int tmp;cin>>tmp;
if(tmp) query[i].pb(tmp);
}
len[i]=query[i].size();
for(int j=0;j<len[i];++j) {
value[i] = value[i]*seed + query[i][j];
}
}
int cnt=0;
for(int i=1;i<=n;++i) {
int pos=-1;
for(int j=1;j<=cnt;++j) {
if(cache[j]==a[i]) {
pos=j;
break;
}
}
if(pos==-1) {
for(int j=cnt;j;--j) {
cache[j+1]=cache[j];
}
cache[1] = a[i];
cnt++;
} else {
for(int j=pos-1;j;--j) {
cache[j+1]=cache[j];
}
cache[1] = a[i];
}
for(int j=1;j<=cnt;++j) {
_hash[j]=_hash[j-1]*seed+cache[j];
}
for(int j=1;j<=q;++j) {
if(gethash(1,len[j])==value[j]) vis[j]=1;
}
}
for(int i=1;i<=q;++i) {
if(vis[i]) cout<<"Yes"<<endl;
else cout<<"No"<<endl;
}
}
}
2018-19ICPC焦作 H. Can You Solve the Harder Problem?(后缀数组)
题意:给一个数组,求不同连续子序列的最大值的和。
思路:不同连续子序列,考虑后缀数组。首先假设不管是否相同,直接求连续子序列最大值的和,怎么求。枚举区间的左端点,设以
i
i
i为左端点的所有区间的最大值的和为
d
p
[
i
]
dp[i]
dp[i]。有
d
p
[
i
]
=
d
p
[
j
]
+
a
[
i
]
∗
(
j
−
i
)
dp[i]=dp[j]+a[i]*(j-i)
dp[i]=dp[j]+a[i]∗(j−i),其中
j
j
j为
i
i
i右边第一个值大于
i
i
i的位置。这个位置(设为
r
i
g
[
i
]
rig[i]
rig[i])可以通过单调栈求。
d
p
dp
dp数组可以通过从右往左扫求。
现在考虑怎么处理相同连续子序列不重复计算的问题。
我们知道一个后缀的height值表示这个前缀(子串)在前面的后缀中出现过。那么对于这个后缀中的子串,我们只统计长度大于height值的前缀的贡献即可。
以
i
i
i为左端点的贡献为
a
[
j
]
∗
(
r
i
g
[
j
]
−
(
i
+
h
e
i
g
h
t
−
1
)
−
1
)
+
d
p
[
r
i
g
[
j
]
]
a[j]*(rig[j]-(i+height-1)-1)+dp[rig[j]]
a[j]∗(rig[j]−(i+height−1)−1)+dp[rig[j]],其中
j
j
j为
[
i
,
i
+
h
e
i
g
h
t
−
1
]
[i,i+height-1]
[i,i+height−1]区间的最大值的位置,可以通过线段树求(因为是静态的,也可以用ST表)。
因为求
h
e
i
g
h
t
height
height数组的板子有点初始化的问题导致调了一个小时
//
// Created by Artist on 2021/10/30.
//
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
#define mkp make_pair
#define fi first
#define se second
#define pb push_back
#define all(x) x.begin(),x.end()
#define DB1(args...) do { cout << #args << " : "; dbg(args); } while (0)
#define endl '\n'
void dbg() { std::cout << " #\n"; }
template<typename T, typename...Args>
void dbg(T a, Args...args) {
std::cout << a << ' ';
dbg(args...);
}
void io() { ios::sync_with_stdio(0), cin.tie(0), cout.tie(0); }
#define typeinput int
inline char nc() {
static char buf[1000000], *p1 = buf, *p2 = buf;
return p1 == p2 && (p2 = (p1 = buf) + fread(buf, 1, 1000000, stdin), p1 == p2) ? EOF : *p1++;
}
inline void read(typeinput &sum) {
char ch = nc();
sum = 0;
while (!(ch >= '0' && ch <= '9')) ch = nc();
while (ch >= '0' && ch <= '9') sum = (sum << 3) + (sum << 1) + (ch - 48), ch = nc();
}
const int maxn = 2e5+5;
int a[maxn],q[maxn];
int rig[maxn]; // 右边第一个比他大的位置
ll dp[maxn]; // 以当前作为l的值的和
stack<pair<int,int>> st; // 单调栈
int sa[maxn],rk[maxn],oldrk[maxn<<1],id[maxn],px[maxn],cnt[maxn];
int ht[maxn];
bool cmp(int x,int y,int w) {
return oldrk[x] == oldrk[y] && oldrk[x+w] == oldrk[y+w];
}
// 这东西值域有点大,离散化
void getheight(int n,int m) {
int i,w,p,k;
for(i=1;i<=m;++i) cnt[i]=0;
for(i=1;i<=n;++i) ++cnt[rk[i]=a[i]];
for(i=1;i<=m;++i) cnt[i] += cnt[i-1];
for(i=n;i;--i) sa[cnt[rk[i]]--] = i;
for(w=1;;w<<=1,m=p) {
for(p=0,i=n;i>n-w;--i) id[++p] = i;
for(i=1;i<=n;++i) if(sa[i]>w) id[++p] = sa[i]-w;
memset(cnt,0,sizeof(cnt));
for(i=1;i<=n;++i) ++cnt[px[i]=rk[id[i]]];
for(i=1;i<=m;++i) cnt[i] += cnt[i-1];
for(i=n;i>=1;--i) sa[cnt[px[i]]--] = id[i];
memcpy(oldrk,rk,sizeof(rk));
for(p=0,i=1;i<=n;++i) rk[sa[i]] = cmp(sa[i],sa[i-1],w)?p:++p;
if(p==n) {
for(int i=1;i<=n;++i) sa[rk[i]] = i;
break;
}
}
for(i=1,k=0;i<=n;++i) {
if(k) --k;
while(sa[rk[i]-1]+k<=n && a[i+k]==a[sa[rk[i]-1]+k]) ++k;
ht[rk[i]] = k;
}
}
int ql,qr;
int pos[maxn<<2];
#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1
int query(int l,int r,int rt) {
if(ql<=l&&qr>=r) {
return pos[rt];
}
int mid=l+r>>1;
int ret=0;
if(ql<=mid) {
int tmp=query(lson);
if(a[tmp]>a[ret]) ret=tmp;
}
if(qr>mid) {
int tmp=query(rson);
if(a[tmp]>a[ret]) ret=tmp;
}
return ret;
}
void build(int l,int r,int rt) {
if(l==r) {
pos[rt] = l;
return;
}
int mid=l+r>>1;
build(lson);
build(rson);
if(a[pos[rt<<1]]>a[pos[rt<<1|1]]) pos[rt]=pos[rt<<1];
else pos[rt]=pos[rt<<1|1];
}
signed main() {
io();
int t;cin>>t;
while(t--) {
int n;cin>>n;
for(int i=1;i<=n;++i) {
cin>>a[i];
q[i] = a[i];
}
// 离散化
sort(q+1,q+1+n);
int tot = unique(q+1,q+1+n)-q-1;
for(int i=1;i<=n;++i) a[i] = lower_bound(q+1,q+1+tot,a[i])-q;
// 单调栈
dp[n+1]=0;
while(st.size()) st.pop();
st.push(mkp(1e7,n+1));
for(int i=n;i;--i) {
while(st.size() && st.top().fi < a[i]) st.pop();
rig[i] = st.top().se;
dp[i] = dp[rig[i]] + 1ll*q[a[i]]*(rig[i]-i);
st.push(mkp(a[i],i));
}
// height数组
getheight(n,tot);
// 查询区间
ll ans = 0;
build(1,n,1);
for(int i=1;i<=n;++i) {
// i-ht[i]中最大值的位置
// 以及该位置的rig
if(ht[rk[i]]==0) {
ans += dp[i];
continue;
}
ql = i,qr = i+ht[rk[i]]-1;
int j = query(1,n,1);
ans += dp[rig[j]]+1ll*q[a[j]]*(rig[j]-i-ht[rk[i]]);
}
cout<<ans<<endl;
}
}
Journey among Railway Stations(线段树)
标程:带着结构体跑。
#include<bits/stdc++.h>
#define N 1000005
using namespace std;
typedef long long LL;
const LL oo = 1e12;
struct Function{
LL l, r, t; int valid;
Function():l(0), r(0), t(0), valid(0){}
Function(LL l_, LL r_, LL t_):l(l_), r(r_), t(t_), valid(1){}
}a[N << 2], ans;
int st[N], ed[N], dist[N];
Function Merge(const Function &A, const Function &B, int d){
if (!A.valid || !B.valid || A.t + d > B.r) return Function();
//if (A.t + d + A.r - A.l <= B.l) return Function(A.r, A.r, B.t);
LL newr = A.t + d + A.r - A.l > B.r ? B.r + A.l - A.t - d : A.r, newl, newt;
if (A.t + d >= B.l) newl = A.l, newt = B.t + A.t + d - B.l;
else newl = min(newr, A.l + B.l - A.t - d), newt = B.t;
return Function(newl, newr, newt);
}
void build(int x, int l, int r){
if (l == r){
a[x] = Function(st[l], ed[l], st[l]);
//printf("%d %d %lld %lld %lld %d\n", l, r, a[x].l, a[x].r, a[x].t, a[x].valid);
return;
}
int mid = (l + r) >> 1;
build(x << 1, l, mid);
build(x << 1 | 1, mid + 1, r);
a[x] = Merge(a[x << 1], a[x << 1 | 1], dist[mid]);
//printf("%d %d %lld %lld %lld %d\n", l, r, a[x].l, a[x].r, a[x].t, a[x].valid);
}
void UpdateDist(int x, int l, int r, int pos){
if (l == r) return;
int mid = (l + r) >> 1;
if (pos < mid) UpdateDist(x << 1, l, mid, pos);
if (pos > mid) UpdateDist(x << 1 | 1, mid + 1, r, pos);
a[x] = Merge(a[x << 1], a[x << 1 | 1], dist[mid]);
}
void UpdateNode(int x, int l, int r, int pos){
if (l == r){
a[x] = Function(st[l], ed[l], st[l]);
return;
}
int mid = (l + r) >> 1;
if (pos <= mid) UpdateNode(x << 1, l, mid, pos);
else UpdateNode(x << 1 | 1, mid + 1, r, pos);
a[x] = Merge(a[x << 1], a[x << 1 | 1], dist[mid]);
}
void Query(int x, int l, int r, int ql, int qr){
if (ql <= l && r <= qr){
if (ql == l) ans = a[x]; else ans = Merge(ans, a[x], dist[l-1]);
return;// TODO: test
}
int mid = (l + r) >> 1;
if (ql <= mid) Query(x << 1, l, mid, ql, qr);
if (qr > mid) Query(x << 1 | 1, mid + 1, r, ql, qr);
}
int main(){
//freopen("sample.txt", "r", stdin);
int T; scanf("%d", &T);
while (T--){
int n; scanf("%d", &n);
for (int i = 1; i <= n; i++)
scanf("%d", &st[i]);
for (int i = 1; i <= n; i++)
scanf("%d", &ed[i]);
for (int i = 1; i < n; i++)
scanf("%d", &dist[i]);
build(1, 1, n);
int Q; scanf("%d", &Q);
while (Q--){
int type; scanf("%d", &type);
if (!type){
int l, r; scanf("%d%d", &l, &r);
// ans = Function(-oo, oo, -oo);
Query(1, 1, n, l, r);
puts(ans.valid ? "Yes" : "No");
}
else if (type == 1){
int pos, new_dist;
scanf("%d%d", &pos, &new_dist);
assert(pos >= 1 && pos < n);
dist[pos] = new_dist;
UpdateDist(1, 1, n, pos);
}
else{
int pos; scanf("%d", &pos);
scanf("%d%d", &st[pos], &ed[pos]);
UpdateNode(1, 1, n, pos);
}
}
}
}
法2:很自然的思路,但是我没想到怎么处理合并以及区间末尾变化这一点。
区间末尾变化:将v也附带上cost的后缀。
合并:只需要判断是否left u’<right v’
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 1e6+5;
const int oo = 2e9;
struct node{
ll mxu,mnv;
int ok;
node():mxu(0),mnv(oo),ok(1){}
node(ll mx,ll mn,int o):mxu(mx),mnv(mn),ok(o){}
}a[maxn<<2],ans;
ll lzy[maxn<<2];
int u[maxn],v[maxn],cost[maxn];
ll suf[maxn]; // 后缀cost
int ql,qr,w,p,q;
node merge(node &ls,node &rs) {
int okk;
ll mx,mn;
if(ls.ok&&rs.ok&&ls.mxu<=rs.mnv) okk=1;
else okk=0;
mx=max(ls.mxu,rs.mxu);
mn=min(ls.mnv,rs.mnv);
return node(mx,mn,okk);
}
// 对cost进行修改,那么在他前面,(包括他这个位置)的u以及v都进行改变
void push_down(int l,int r,int rt) {
if(lzy[rt]) {
a[rt<<1].mnv+=lzy[rt]; // w是改变值
a[rt<<1].mxu+=lzy[rt];
lzy[rt<<1]+=lzy[rt];
a[rt<<1|1].mnv+=lzy[rt]; // w是改变值
a[rt<<1|1].mxu+=lzy[rt];
lzy[rt<<1|1]+=lzy[rt];
lzy[rt]=0;
}
}
void build(int l,int r,int rt) {
if(l==r) {
a[rt] = node(suf[l]+u[l],suf[l]+v[l],1);
lzy[rt] = 0;
return;
}
int mid=l+r>>1;
build(l,mid,rt<<1);
build(mid+1,r,rt<<1|1);
a[rt] = merge(a[rt<<1],a[rt<<1|1]);
lzy[rt] = 0;
}
void chcost(int l,int r,int rt) {
// cout<<l<<" "<<r<<endl;
if(ql<=l&&qr>=r) {
a[rt].mnv += w;
a[rt].mxu += w;
lzy[rt] += w;
return;
}
push_down(l,r,rt);
int mid=l+r>>1;
if(ql<=mid) chcost(l,mid,rt<<1);
if(qr>mid) chcost(mid+1,r,rt<<1|1);
a[rt] = merge(a[rt<<1],a[rt<<1|1]);
}
void chuv(int l,int r,int rt) {
if(l==r) {
a[rt].mxu+=p; // 改变量
a[rt].mnv+=q;
return;
}
push_down(l,r,rt);
int mid=l+r>>1;
if(ql<=mid) chuv(l,mid,rt<<1);
else chuv(mid+1,r,rt<<1|1);
a[rt]=merge(a[rt<<1],a[rt<<1|1]);
}
void query(int l,int r,int rt) {
if(ql<=l&&qr>=r) {
if(ql==l) ans=a[rt];
else ans=merge(ans,a[rt]);
return;
}
int mid=l+r>>1;
push_down(l,r,rt);
if(ql<=mid) query(l,mid,rt<<1);
if(qr>mid) query(mid+1,r,rt<<1|1);
}
int main() {
int t;scanf("%d",&t);
while(t--) {
int n;scanf("%d",&n);
for(int i=1;i<=n;++i) scanf("%d",&u[i]);
for(int i=1;i<=n;++i) scanf("%d",&v[i]);
for(int i=1;i<n;++i) scanf("%d",&cost[i]);
int qq;scanf("%d",&qq);
suf[n]=0;
for(int i=n-1;i;--i) suf[i]=suf[i+1]+cost[i];
build(1,n,1);
while(qq--) {
int opt;scanf("%d",&opt);
if(!opt) {
scanf("%d%d",&ql,&qr);
query(1,n,1);
if(ans.ok) printf("Yes\n");
else printf("No\n");
} else if(opt==1) {
int nw;
ql=1;
scanf("%d%d",&qr,&nw);
w = nw-cost[qr];
cost[qr] = nw;
chcost(1,n,1);
} else {
int np,nq;
scanf("%d%d%d",&ql,&np,&nq);
p = np-u[ql],q = nq-v[ql];
u[ql]=np,v[ql]=nq;
chuv(1,n,1);
}
}
}
}