zoukankan      html  css  js  c++  java
  • 洛谷 4135 作诗——分块

    题目:https://www.luogu.org/problemnew/show/P4135

    和“历史研究”一样的定义。但因为只能开下一个nsqrt(n)的数组,所以答案记录成第 i 块到第 j 块的。

    用数组记录每一块的开始位置和结束位置也许比较好。

    不用sta记录要把哪些nm赋0,而是在使用nm之前把要使用的nm手动赋初值也许比较好。

    注意预处理 f 数组的时候要开一个tmp,不要直接在 f 上加加减减的,不然第二维一变就要出错了。

    然而还是被WA和RE虐。

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<cmath>
    using namespace std;
    const int N=1e5+5,M=320;
    int n,m,c,a[N],ans,base,bh[N],nm[N];
    int bst[M],bed[M],cnt[M][N],f[M][M];
    void init()
    {
      for(int i=1;i<=bh[n];i++)
      {
            int tmp=0,tem=i;
            memset(nm,0,sizeof nm);
            bst[i]=(i-1)*base+1;bed[i]=min(n,i*base);
            for(int j=1;j<=c;j++)cnt[i][j]=cnt[i-1][j];
            for(int j=bst[i];j<=bed[i];j++)cnt[i][a[j]]++;
          for(int j=bst[i];j<=n;j++)//i not bh[i]!!!
        {
          nm[a[j]]++;
          if(nm[a[j]]&1){if(nm[a[j]]!=1)tmp--;}else tmp++;
          if(j==bed[tem])f[i][tem]=tmp,tem++;
            
            
    //      cnt[i][a[j]]++;
    //      if(cnt[i][a[j]]&1){if(cnt[i][a[j]]!=1)tmp--;}else tmp++;
    //      if(j==bed[tem])f[i][tem]=tmp,tem++;
    
    
    //      if(cnt[i][a[j]]==1)continue;
    //      if(cnt[i][a[j]]&1)f[i][bh[j]]--;else f[i][bh[j]]++;//不要这样!不然bh[j+1]没有继承bh[j]的! 
    
        }
      }
    }
    int main()
    {
      scanf("%d%d%d",&n,&c,&m);base=sqrt(n);
      for(int i=1;i<=n;i++)scanf("%d",&a[i]),bh[i]=(i-1)/base+1;
      init();int x,y;
      while(m--)
        {
          scanf("%d%d",&x,&y);
          x=(x+ans)%n+1;y=(y+ans)%n+1;
          if(x>y)swap(x,y);
          if(bh[y]-bh[x]==0)//!!
        {
          ans=0;
          for(int i=x;i<=y;i++)nm[a[i]]=0;
          for(int i=x;i<=y;i++)
            {
              nm[a[i]]++;
              if(nm[a[i]]==1)continue;
              if(nm[a[i]]&1)ans--;else ans++;
            }
          printf("%d
    ",ans);continue;
        }
          ans=f[bh[x]+1][bh[y]-1];//bh[x]+1!!!
          if(bh[y]-bh[x]==1)ans=0;//
    //      for(int i=bst[bh[y]];i<=y;i++)nm[a[i]]=cnt[bh[x]+1][a[i]]-cnt[bh[y]][a[i]];
    //      for(int i=x;i<=bed[bh[x]];i++)nm[a[i]]=cnt[bh[x]+1][a[i]]-cnt[bh[y]][a[i]];
          for(int i=bst[bh[y]];i<=y;i++)nm[a[i]]=cnt[bh[y]-1][a[i]]-cnt[bh[x]][a[i]];
          for(int i=x;i<=bed[bh[x]];i++)nm[a[i]]=cnt[bh[y]-1][a[i]]-cnt[bh[x]][a[i]];
          for(int i=bst[bh[y]];i<=y;i++)
          {
              nm[a[i]]++;
              if(nm[a[i]]==1)continue;
              if(nm[a[i]]&1)ans--;else ans++;
          }
          for(int i=x;i<=bed[bh[x]];i++)
        {
          nm[a[i]]++;
          if(nm[a[i]]==1)continue;
          if(nm[a[i]]&1)ans--;else ans++;
        }
          printf("%d
    ",ans);
        }
      return 0;
    }
    View Code

    这份能AC的代码和上面又有什么不同呢?有毒……

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<cmath>
    using namespace std;
    const int N=1e5+5,M=320;
    int n,m,c,a[N],ans,base,bh[N],nm[N];
    int bst[M],bed[M],cnt[M][N],f[M][M];
    void init(int cr)
    {
        int tmp=0,tem=cr;
        memset(nm,0,sizeof nm);
        for(int i=bst[cr];i<=n;i++)
        {
            nm[a[i]]++;
            if(nm[a[i]]&1){if(nm[a[i]]!=1)tmp--;}else tmp++;
            if(i==bed[tem])f[cr][tem]=tmp,tem++;
        }
    }
    int main()
    {
      scanf("%d%d%d",&n,&c,&m);base=sqrt(n);
      for(int i=1;i<=n;i++)scanf("%d",&a[i]),bh[i]=(i-1)/base+1;
      for(int i=1;i<=bh[n];i++)bst[i]=(i-1)*base+1,bed[i]=min(n,i*base);
      for(int i=1;i<=bh[n];i++)init(i);
      for(int i=1;i<=bh[n];i++)
      {
          for(int j=1;j<=c;j++)cnt[i][j]=cnt[i-1][j];
          for(int j=bst[i];j<=bed[i];j++)cnt[i][a[j]]++;
      }
      int x,y;
      while(m--)
        {
          scanf("%d%d",&x,&y);
          x=(x+ans)%n+1;y=(y+ans)%n+1;
          if(x>y)swap(x,y);
          if(bh[y]-bh[x]==0)//!!
        {
          ans=0;
          for(int i=x;i<=y;i++)nm[a[i]]=0;
          for(int i=x;i<=y;i++)
            {
              nm[a[i]]++;
              if(nm[a[i]]==1)continue;
              if(nm[a[i]]&1)ans--;else ans++;
            }
          printf("%d
    ",ans);continue;
        }
          ans=f[bh[x]+1][bh[y]-1];//bh[x]+1!!!
          if(bh[y]-bh[x]==1)ans=0;//
          for(int i=bst[bh[y]];i<=y;i++)nm[a[i]]=cnt[bh[y]-1][a[i]]-cnt[bh[x]][a[i]];
          for(int i=x;i<=bed[bh[x]];i++)nm[a[i]]=cnt[bh[y]-1][a[i]]-cnt[bh[x]][a[i]];
          for(int i=bst[bh[y]];i<=y;i++)
          {
              nm[a[i]]++;
              if(nm[a[i]]==1)continue;
              if(nm[a[i]]&1)ans--;else ans++;
          }
          for(int i=x;i<=bed[bh[x]];i++)
        {
          nm[a[i]]++;
          if(nm[a[i]]==1)continue;
          if(nm[a[i]]&1)ans--;else ans++;
        }
          printf("%d
    ",ans);
        }
      return 0;
    }
  • 相关阅读:

    暴力求解/数学问题
    Leetcode207. Course Schedule
    Balanced Team
    由先序和中序求后序
    Median String
    树的同构
    uva 202
    整除光棍
    阅览室
  • 原文地址:https://www.cnblogs.com/Narh/p/9302588.html
Copyright © 2011-2022 走看看