您的位置:首页 > 其它

zoj 2900 DP(线段树优化)

2014-04-12 10:52 381 查看
同样是暴力,别人能过,我不能过,生活有的时候就是这么无奈。

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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: