zoj 2900 DP(线段树优化)

来源:互联网 发布:golang web框架 编辑:程序博客网 时间:2024/05/02 00:30

同样是暴力,别人能过,我不能过,生活有的时候就是这么无奈。

dp【i】【j】【k】表示前i个数取j个,最后一和是k的个数

然后改变dp顺序可以将三维变为2维

注意下一下细节的地方。。。。不然这样暴力DP会超时

还有一种就是用线段树来优化。。。。。优化到3770ms。。。。。

不优化是6000+ms。。。。

有一点要注意的就是不能一个都没有。。。

AC代码如下:

线段树优化:

#include <iostream>#include <cstring>#include <cstdio>#include <algorithm>using namespace std;int dp[2200][110];int N, K, P, M;int num[2200];int now;int sum[2200][1000];int lc( int root ){    return 2 * root;}int rc( int root ){    return 2 * root + 1;}void Up( int pos, int root ){    sum[pos][root] = ( sum[pos][lc(root)] + sum[pos][rc(root)] ) % M;}void Updata( int pos, int k, int number, int l, int r, int root ){    if( l == k && r == k ){        sum[pos][root] = number % M;        return;    }    int mid = ( l + r ) / 2;    if( k <= mid )  Updata( pos, k, number, l, mid, lc( root ) );    else    Updata( pos, k, number, mid + 1, r, rc( root ) );    Up( pos, root );}int query( int pos, int L, int R, int l, int r, int root ){    if( L <= l && R >= r ){        return sum[pos][root];    }    int ans = 0;    int mid = ( l + r ) / 2;    if( L <= mid )  ans = ( ans + query( pos, L, R, l, mid, lc( root ) ) ) % M;    if( R >= mid + 1 )  ans = ( ans + query( pos, L, R, mid + 1, r, rc( root ) ) ) % M;    return ans % M;}int main(){    while( scanf( "%d%d%d%d", &N, &K, &P, &M ) != EOF ){        int ttmax = 0;        int ttmin = 100;        for( int i = 1; i <= N; i++ ){            scanf( "%d", &num[i] );            ttmax = max( ttmax, num[i] );            ttmin = min( ttmin, num[i] );        }        memset( dp, 0, sizeof( dp ) );        memset( sum, 0, sizeof( sum ) );        for( int i = 1; i <= N; i++ ){            for( int j = i; j >= 1; j-- ){                if( j == 1 ){                    dp[j][num[i]] = ( dp[j][num[i]] + 1 ) % M;                    Updata( j, num[i], dp[j][num[i]], 0, 100, 1 );                }                int temp = 0, a, b;                a = num[i] - P;                if( a < ttmin ) a = ttmin;                b = num[i] + P;                if( b > ttmax ) b = ttmax;                temp = query( j - 1, a, b, 0, 100, 1 );                dp[j][num[i]] = ( dp[j][num[i]] + temp ) % M;                Updata( j, num[i], dp[j][num[i]], 0, 100, 1 );            }        }        int ans = 0;        for( int i = K == 0 ? 1 : K; i <= N; i++ ){            ans = ( ans + query( i, 0, 100, 0, 100, 1 ) ) % M;        }     //   if( K == 0 )    ans = ( ans + 1 ) % M;        cout << ans << endl;    }    return 0;}

没用线段树优化的话要注意一些细节。。。。

#include <iostream>#include <cstring>#include <cstdio>#include <algorithm>using namespace std;int dp[2200][110];int N, K, P, M;int num[2200];int now;int main(){    while( scanf( "%d%d%d%d", &N, &K, &P, &M ) != EOF ){        int ttmax = 0;        for( int i = 1; i <= N; i++ ){            scanf( "%d", &num[i] );            ttmax = max( ttmax, num[i] );        }        memset( dp, 0, sizeof( dp ) );        for( int i = 1; i <= N; i++ ){            for( int j = i; j > 1; j-- ){                int temp = 0;                for( int k = num[i] - P; k <= num[i] + P && k <= ttmax; k++ ){                    if( k < 1 ) continue;                    temp = ( temp + dp[j-1][k] ) % M;                }                dp[j][num[i]] = ( dp[j][num[i]] + temp ) % M;            }            dp[1][num[i]]++;        }        int ans = 0;        for( int i = K == 0 ? 1 : K; i <= N; i++ ){            for( int j = 0; j <= ttmax; j++ ){                ans = ( ans + dp[i][j] ) % M;            }        }       // if( K == 0 )    ans++;        cout << ans << endl;    }    return 0;}


0 0
原创粉丝点击