[Group] NOIP2015 improve substring array optimization rolling section DP +

Meaning of the questions:

Contains only two strings lowercase letters  A  and  B.

Now the string from  A  Remove the  k-th non-overlapping non-empty strings, and these  k  substrings in the character string in accordance with its  A  sequence appear sequentially connected get a new string.

I wonder how many kinds of programs can make this new string and string  B  are equal?

Note: substring withdrawn position different from different schemes are also considered.

 

data range:

For the data set 1: 1≤n≤500,1≤m≤50, K = 1 ;
for Group 2 to Group 3 data: 1≤n≤500,1≤m≤50, K = 2
to 4 group 5 to group data: 1≤n≤500,1≤m≤50, K = m
for group 1 to group 7 data: 1≤n≤500,1≤m≤50,1≤k≤m
for group 1 to group 9 data: 1≤n≤1000,1≤m≤100,1≤k≤m
for all 10 sets of data: 1≤n≤1000,1≤m≤200,1≤k≤m

-------------------------------------------------- ---- I am dividing line ------------------------------------------ ----------

Solution: a state less obvious problem, we must first find the entry point of solving the problem.

This question is observed characteristics, we found that, with respect to B, A each character is clearly the election and not vote for two kinds of decisions.

For the two strings can be expressed by two pointers, pointing to a state A, a state B point.

This question is then very state was found.

Set status:

Provided F (i, j, k, 1) denotes the front i-th character of A, B, matched to the current j-th character, using a total of k segments, the number of the program currently selected i-th character.

F (i, j, k, 0) denotes the front i-th character of A, B, matched to the current j-th character, using a total of k segments, this embodiment does not select the number of the i-th character.

Then is the state transition:

By the state, we may infer the state transition equation as follows:

(1) When the time Ai == Bj, F (i, j, k, 0) = F (i-1, j, k, 0) + F (i-1, j, k, 1).

     I.e., the sum of Scheme A i-1 before the i-th program number does not answer a number == current.

           F(i,j,k,1) = F(i-1,j-1,k-1,0) + F(i-1,j-1,k-1,1) + F(i-1,j-1,k,1);

     I.e., the current program number as the answer in the i-th A == A i-1 before the number of hits to the sum of a number of programs in the first-1 j B (i does not answer to the previous) + A front program number i-1 (i to the previous answer).  

(2) when Ai! = Bj time, F (i, j, k, 0) = F (i-1, j-1, k, 0) + F (i-1, j-1, k, 1) .

     Transfer with (1).

           F(i,j,k,1) = 0;  

   Given the current number as the answer can not be, so the program is zero.

And then determine the boundary conditions, we can know, F (i, 0,0,0) = 1; i.e. 0 B match characters in scheme 1.

So we can write the code:

#include<bits/stdc++.h>

#define ll long long
#define mp make_pair
#define rep(i, a, b) for(int i = (a); i <= (b); i++)
#define per(i, a, b) for(int i = (a); i >= (b); i--)

using namespace std;

typedef pair<int, int> pii;
typedef double db;
const int mod = 1e9+7;
const int N = 1e6 + 50;
int n, m, p;
int f[1010][101][101][2];
char a[N], b[N];
inline int read() {
    int x = 0, f = 1;
    char ch = getchar();
    while(ch < '0' || ch > '9') { if(ch == '-') f = -1; ch = getchar();}
    while(ch >='0' && ch <='9') { x = (x<<3)+(x<<1)+(ch^48); ch = getchar();}
    return x*f;
}
void work(){
    rep(i, 0, n) f[i][0][0][0] = 1;
    rep(i, 1, n) rep(j, 1, m) rep(k, 1, p){
        if(a[i] == b[j]) {
            f[i][j][k][0] = (f[i-1][j][k][0] + f[i-1][j][k][1])%mod;
            f[i][j][k][1] = (f[i-1][j-1][k-1][0] + (f[i-1][j-1][k-1][1] + f[i-1][j-1][k][1]) % mod) % mod;
        }
        else {
            f[i][j][k][1] = 0;
            f[i][j][k][0] = (f[i-1][j][k][0] + f[i-1][j][k][1])%mod;
        }
    }
    printf("%d\n", (f[n][m][p][1] + f[n][m][p][0])%mod); 
}
void init(){
    n = read(); m = read(); p = read();
    scanf("%s%s", a+1, b+1);
}
int main(){
    init(); 
    work();
    return 0;
}
View Code

但是我们发现,这份代码空间复杂度效率低下(2*n*m*k),无法通过此题,我们还需要优化。

于是乎,DP常用的空间优化:滚动数组优化就出现了。

观察DP转移方程,我们可以发现,每一个决策i只与前一个决策i-1有关,其他的空间都是多余的。

所以我们就可以用01方法表示。

AC代码如下:

#include<bits/stdc++.h>

#define ll long long
#define mp make_pair
#define rep(i, a, b) for(int i = (a); i <= (b); i++)
#define per(i, a, b) for(int i = (a); i >= (b); i--)

using namespace std;

typedef pair<int, int> pii;
typedef double db;
const int mod = 1e9 + 7;
const int N = 1e6 + 50;
int n, m, p;
int f[2][220][220][2];
char a[N], b[N];
inline int read() {
    int x = 0, f = 1;
    char ch = getchar();
    while(ch < '0' || ch > '9') { if(ch == '-') f = -1; ch = getchar();}
    while(ch >='0' && ch <='9') { x = (x<<3)+(x<<1)+(ch^48); ch = getchar();}
    return x*f;
}
void work(){
    int val = 1;
    f[0][0][0][0] = f[1][0][0][0] = 1; 
    rep(i, 1, n) {
        rep(j, 1, m) rep(k, 1, p){
            if(a[i] == b[j]) {
                f[val][j][k][0] = (f[val^1][j][k][0] + f[val^1][j][k][1])%mod;
                f[val][j][k][1] = (f[val^1][j-1][k-1][0] + (f[val^1][j-1][k-1][1] + f[val^1][j-1][k][1]) % mod) % mod;
            }
            else {
                f[val][j][k][1] = 0;
                f[val][j][k][0] = (f[val^1][j][k][0] + f[val^1][j][k][1])%mod;
            }
        }
        val ^= 1;
    }
    printf("%d\n", (f[n&1][m][p][1] + f[n&1][m][p][0])%mod); 
}
void init(){
    n = read(); m = read(); p = read();
    scanf("%s%s", a+1, b+1);
}
int main(){
    init(); 
    work();
    return 0;
}
View Code

总结:这道题作为线性DP的练习题(NOIP的题),有一定的思维难度,对DP思维提升有很大的帮助。

Guess you like

Origin www.cnblogs.com/smilke/p/11587313.html