UESTC 1256 昊昊喜欢运动 n^2的预处理 or 前缀和

ProLightsfx 2015-12-5 124 12/5

           

昊昊爱运动 n^2的预处理 or 前缀和

Source

第七届ACM趣味程序设计竞赛第二场(正式赛) A

My Solution

1、当时把时间改成3000MS
所以直接暴力,过去,用一个数字cot[108],来记录每个区间内的任务是否在区间类出现过。
现在时间突然该回来了,所以 嘿嘿,我只是记录一下自己的代码☺☺
☺☺
☺☺
#include 
#include 
#include 
#define LOCAL
using namespace std;
int n[2008],cot[108];
int main()
{
    #ifdef LOCAL
    freopen("a.txt","r",stdin);
    #endif // LOCAL
    int N,M,Q,x,y,cott;
    scanf("%d%d",&N,&M);
    for(int i=1;i<=N;i++){
        scanf("%d",&n[i]);
    }

    scanf("%d",&Q);
    while(Q--){
        cott=0;
        memset(cot,0,sizeof(cot));
        scanf("%d%d",&x,&y);
        for(int i=x;i<=y;i++)
            if(cot[n[i]]==0) {cott++;cot[n[i]]++;}
        //for(int j=0;j<=M;j++)
        //    if(cot[j]!=0) ;
        printf("%d",cott);
        if(Q) printf("n");

    }
    return 0;
}
2、用n^2的预处理,直接搞出ans[i][j],然后O(1)的询问
当时2000的平方算成1e8级了,☺☺,事实上是1e6级。
#include 
#include 
//#define LOCAL
using namespace std;
const int maxn=2000+2;
int n[maxn],cot[108],ans[maxn][maxn];
int main()
{
    #ifdef LOCAL
    freopen("a.txt","r",stdin);
    #endif // LOCAL
    int N,M,Q,x,y,cott;
    scanf("%d%d",&N,&M);
    for(int i=1;i<=N;i++){
        scanf("%d",&n[i]);
    }
    //ans[maxn][maxn]就不用memset了,由于这里没有必要,而且数组比较大,memset起来还是要耗点时间的
    //n^2的预处理
    for(int i=1;i<=N;i++){
        memset(cot,0,sizeof(cot));cott=0;
        for(int j=i;j<=N;j++){
            if(cot[n[j]]==0) {cott++;cot[n[j]]++;}
            ans[i][j]=cott;//由于这里指的是[x,y],且1<=x,所以上面要用 int i=1;i<=N;i++,下面j也是
        }   //数组和所需要对应好
    }
    //询问
    scanf("%d",&Q);
    while(Q--){
        scanf("%d%d",&x,&y);
        printf("%d",ans[x][y]);
        if(Q) printf("n");
    }
    return 0;
}

3、前缀和思想

在输入的时候直接维护ans[ i ][ j ],表示在[1,i ]中j 出现了多少次,维护的时候注意把前一个的所有信息都要维护的这一项;
然后每次询问扫M,判断ans[ y ][ i ]-ans[ x-1 ][ i ]是否大于0 。用cott计数;
#include 
#include 
#define LOCAL
using namespace std;
int ans[2002][108];
int main()
{
    #ifdef LOCAL
    freopen("a.txt","r",stdin);
    #endif // LOCAL
    int N,M,Q,x,y,cott,n;
    scanf("%d%d",&N,&M);
    memset(ans,0,sizeof(ans));
    for(int i=1;i<=N;i++){
        scanf("%d",&n);                                //原来的n[maxn]也可以省掉了
        ans[i][n]++;
        for(int j=1;j<=M;j++) ans[i][j]+=ans[i-1][j];  //边输入边维护 前面的所有信息都要维护过来1-M的出现次数
        //前面用了j<i,i可能很大,不越界才怪,改的时候,不要漏地方没改
    }

    scanf("%d",&Q);
    while(Q--){
        cott=0;
        scanf("%d%d",&x,&y);
        for(int i=1;i<=M;i++){ if((ans[y][i]-ans[x-1][i])>0) cott++;    //注意索引
        }
        printf("%d",cott);
        if(Q) printf("n");
    }
    return 0;
}

前面数组越界了,返回了一个RF,在不知道是越界引起的时候,我加了个#include 以后返回了WA,嘿嘿挺好玩的。

用前缀和相对n^2预处理memory小了很多,但显然n^2预处理要快一点,
特别是Q比较大,很接近上限的时候,Q->1e6,且n->2000,m->100,O(n*m+Q*m)>>O(n^2+Q)。


非特殊说明,本站所有文章均为博主原创,未经许可不得转载。

https://www.prolightsfxjh.com/

Thank you!

                                                                                                                                             ------from ProLightsfx

- THE END -

ProLightsfx

11月16日08:55

最后修改:2024年11月16日
0

非特殊说明,本博所有文章均为博主原创,未经许可不得转载。

共有 0 条评论