洛谷 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\n",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\n",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\n",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\n",ans);
    }
  return 0;
}

 

posted on 2018-07-12 23:58  Narh  阅读(265)  评论(0编辑  收藏  举报

导航