1. 程式人生 > >Codeforces problem 750E New Year and Old Subsequence

Codeforces problem 750E New Year and Old Subsequence

  我們的目標是得到含有’2017’而不含有’2016’的子序列,有多次查詢,用線段樹解決。線上段樹的每個節點中,開一個5*5的二維陣列arr[i][j],表示該區間為了能夠出現’2017’中的[i,j)子序列而不會出現[i,j]子序列,並且不會出現’2016’,需要刪除的最少字元數。
  比如arr[0][2]表示該區間能夠出現’20’但不能出現’201’需要刪除的最少字元數。又如arr[1][1]表示不會出現’1’。需要注意的是’6’不能出現在[3][3](即’1’之後,’7’之前)和[4][4](即’7’之後)。

#include <bits/stdc++.h>

using namespace
std; #define ll long long const int INF = 1e9; const int maxn = 200010; struct node{ int val[5][5]; node(){ for(int i=0;i<5;i++){ for(int j=0;j<5;j++){ val[i][j] = INF; } } } }tree[maxn<<2]; int n,q; char num[maxn]; char ch[] = {'2'
,'0','1','7','6'}; int find(char c){ for(int i=0;i<5;i++){ if(ch[i]==c)return i; } return -1; } node push_up(node &a,node &b){ node res; for(int i=0;i<5;i++){ for(int j=i;j<5;j++){ for(int k=i;k<=j;k++){ res.val[i][j] = min(res.val[i][j],a.val[i][k]+b.val[k][j]); } } } return
res; } void build_tree(int rt,int l,int r){ if(l==r){ int f = find(num[l]); for(int i=0;i<5;i++){ tree[rt].val[i][i] = 0; } if(f!=-1 && f<4){ tree[rt].val[f][f+1] = 0; tree[rt].val[f][f] = 1; }else if(f==4){ tree[rt].val[3][3] = tree[rt].val[4][4] = 1; } return; } int mid = (l+r)>>1; build_tree(rt<<1,l,mid); build_tree(rt<<1|1,mid+1,r); tree[rt] = push_up(tree[rt<<1],tree[rt<<1|1]); } node query(int rt,int tl,int tr,int l,int r){ if(l==tl && r==tr){ return tree[rt]; } int mid = (tl+tr)>>1; if(r<=mid){ return query(rt<<1,tl,mid,l,r); }else{ if(l>mid){ return query(rt<<1|1,mid+1,tr,l,r); }else{ node tmpl = query(rt<<1,tl,mid,l,mid); node tmpr = query(rt<<1|1,mid+1,tr,mid+1,r); return push_up(tmpl,tmpr); } } } int main(){ cin>>n>>q; scanf("%s",num+1); build_tree(1,1,n); while(q--){ int l,r; scanf("%d %d",&l,&r); node ans = query(1,1,n,l,r); if(ans.val[0][4] == INF){ ans.val[0][4] = -1; } printf("%d\n",ans.val[0][4]); } return 0; }