zoukankan      html  css  js  c++  java
  • P4303 [AHOI2006]基因匹配

    题意


    给定一个两个长度为5n的序列, 保证每个序列1-n各出现5次, 求最长公共子序列
    (n leq 20000)

    题解


    首先, 突破点肯定是每个数只出现5次。
    然后我们开始思考这和普通lcs的区别在于: 能和每个数匹配的至多只有5个数
    我们再看看朴素的lcs, 朴素的lcs设 (f_{i, j}) 表示到s到i, t到j的最长长度, 假如(S_i == T_j) 那么可以他们匹配。
    但事实上: 我们可以假装没学过lcs, 那按照我一贯的dp手法, 一定会分阶段dp;
    我们这样理解,fi,j表示s匹配到i, t匹配到j的最大长度,并且i, j一定要匹配起来的最大值
    fi就表示我们现在要匹配si,那么我们可以用一个线段树来维护状态,
    假如我们完全不匹配, 那么每一个状态就和fi-1,j相等,
    这时候我们开始匹配, 对于5各点中的每一个点x, 我们让

    [f_{i,x} = max(f_{i-1, x}, max_{j}^{i-1}(f_{i-1, j}) + 1) ]

    瞎乱线段树维护一下

    #include <iostream>
    #include <cstdio>
    #define ll long long
    #define l(x) ((x)<<1)
    #define r(x) (l(x)+1) 
    using namespace std;
    
    const int N = 100005;s
    int n, m, a[N];
    ll tree[N<<2], tag[N<<2];
    
    void push_up(int o){
    	tree[o] = tree[l(o)] + tree[r(o)];
    }
    
    void f(int o, int l, int r, int v){
    	tree[o] = 1ll*(r-l+1)*v;
    	tag[o] = v; 
    }
    
    void push_down(int o, int l, int r){
    	int mid = (l+r)/2;
    	f(l(o), l, mid, tag[o]);
    	f(r(o), mid+1, r, tag[o]);
    	tag[o] = 0;
    }
    
    void build(int o, int l, int r){
    	if(l==r){
    		tree[o] = a[l];
    		return ;
    	}
    	
    	int mid = (l+r)/2;
    	build(l(o), l, mid);
    	build(r(o), mid+1, r);
    	push_up(o);
    }
    
    ll query(int o, int l, int r ,int ql, int qr){
    	if(ql<=l&&r<=qr) return tree[o];
    	
    	int mid=(l+r)/2;ll res=0;
    	push_down(o, l, r);
    	if(ql <= mid) res = query(l(o), l, mid, ql, qr);
    	if(qr > mid) res = max(res, )query(r(o), mid+1, r, ql, qr));
    	return res;
    }
    
    void update(int o, int l, int r, int ql, int qr, int v){
    	if(ql<=l&&r<=qr){
    		f(o, l, r, v);
    		return ;
    	}
    	
    	int mid = (l+r)/2;
    	push_down(o, l, r);
    	if(ql<=mid) update(l(o), l, mid, ql, qr, v);
    	if(qr>mid) update(r(o), mid+1, r, ql, qr, v);
    	push_up(o);
    }
    
    ll query(int l, int r){
    	return query(1, 1, n, l, r);
    }
    
    ll update(int l, int r, int v){
    	update(1, 1, n, l, r, v);
    } 
    
    int read(){
    	int num=0, flag=1; char c=-1;
    	while((c<'0' || c>'9')&&c!='-') c=getchar();
    	if(c=='-') flag=-1, c=getchar();
    	while(c>='0' && c<='9') num=num*10+c-'0', c=getchar();
    	return num*flag; 
    } 
    
    int s[N], t[N], p[N][10];
    
    void scan(){
    	n=read()*5;
    	for(int i=1; i<=n; i++){
    		a[i] = 0;
    	}
    	build(1, 1, n);
    	
    	for(int i=1; i<=n; i++){
    		s[i] = read();
    	}
    	for(int i=1; i<=n; i++){
    		t[i] = read();
    		for(int j=1; j<=5; j++){
    			if(!p[t[i]][j]){
    				p[t[i]][j] = i;
    			}
    		}
    	}
    } 
    
    void solve(){
    	
    } 
    
    int main(){
    	scan();
    	solve();
    	return 0;
    } 
    

    什么东西啊, 我自己都看不懂

  • 相关阅读:
    NPM
    Angular2.0快速开始
    AngularJS常用插件与指令收集
    Linq 操作基础
    SQL Server2008 with(lock)用法
    SQL Server2008 MERGE指令用法
    SQL Server2008 表旋转(pivot)技术
    ef to sqlite 实际开发问题终极解决方法
    windows控件常用缩写
    SQL 查询总结
  • 原文地址:https://www.cnblogs.com/ltdjcoder/p/15229492.html
Copyright © 2011-2022 走看看