[NOIP2015] 꼬치

5065 단어 dpnoip
전송문은 경기장에서 이 문제로 인해 많은 시간을 망쳤다.... 아니면 내가 너무 형편없었지만 그래도 잘 썼다.DP의 사고방식은 매우 간단하다. f(k, i, j)는 k단을 나누고 첫 번째 줄의 앞의 i개의 숫자를 사용해서 두 번째 줄의 앞의 j개의 방안수를 구성했다.
f(k, i, j) = ∑f(k-1, l, j-1) ∑f(k-1, l, l, l, j-1) ∑f(k-1, l, j-1) + f(k, i-1, j-1)는 s1[i]==s2[j]이고 s1[i-1]!s2[j-3-1]가 s1[i]==s2[j]이고 s1[i-3-1]==s2[j-31]에서 0첫 번째 이전은 독립적으로 한 부분을 개척할 가능성수이고, 두 번째 이전부터 k개 부분을 나누어 k개 부분을 확대하는 방안수를 포함한다.역시 이해하기 쉽다. 물론 f수 그룹은 1차원으로 굴러야 한다. 그렇지 않으면 메모리가 폭발할 것이다.
나는 이 문제의 난이도가 모두 그 당시의 거북이 바둑과 당시의 난이도와 많이 다르지 않다고 생각한다.그런데 이 문제의 70점 알고리즘은
O(nm2k)는 쓰기가 쉬워서 차이가 안 나요.
제 컨디션이 바뀌는 걸 보고 생각해 낼 수 있을 거라고 믿습니다.
O(nmk) 방법.사실 저희가 지켜야 할 건 그거밖에 없어요.
∑tmp수 그룹으로 저장하면 됩니다(코드 참조)
코드
#include
#include
typedef unsigned int LL;
const LL MOD = 1000000007LL;
const int MAXN = 1005;
int n, m, K;
LL f[2][MAXN][205];
LL tmp[2][MAXN][205];
char s1[MAXN], s2[MAXN];
LL ans = 0;
int main()
{
    scanf("%d%d%d", &n, &m, &K);
    scanf("%s%s", s1+1, s2+1);
    f[0][0][0] = 1;
    tmp[0][0][0] = 1;
    for(int i = 0; i <= n; i ++)
        tmp[0][i][0] = 1;
    for(int k = 1; k <= K; k ++) {
        memset(tmp[k&1], 0, sizeof (tmp[k&1]));
        memset(f[k&1], 0, sizeof (f[k&1]));
        for(int i = 1; i <= n; i ++) {
            for(int j = 1; j <= m; j ++) {
                if(s1[i] == s2[j]) {
                    f[k&1][i][j] = tmp[(k+1)&1][i-1][j-1];
                    if(s1[i-1] == s2[j-1]) f[k&1][i][j] = (f[k&1][i][j] + f[k&1][i-1][j-1]) % MOD;
                    if(f[k&1][i][j] >= MOD) f[k&1][i][j] -= MOD;
                }
                tmp[k&1][i][j] = (tmp[k&1][i][j] + f[k&1][i][j]) % MOD + tmp[k&1][i-1][j];
                if(tmp[k&1][i][j] > MOD) tmp[k&1][i][j] -= MOD;
            }
        }
    }
    for(int i = 1; i <= n; i ++)
        ans = (ans + f[K&1][i][m]) % MOD;
    printf("%d
"
, ans); return 0; }

좋은 웹페이지 즐겨찾기