首页 > 其他分享 >洛谷 P4135 作诗 题解

洛谷 P4135 作诗 题解

时间:2022-11-12 19:34:14浏览次数:69  
标签:tim 洛谷 分块 int 题解 else -- ans P4135

题面

之前做过一道很类似的题目 洛谷P4168蒲公英 ,然后看到这题很快就想到了解法,做完这题可以对比一下,真的很像。

题目要求区间内出现次数为正偶数的数字的数量。

数据范围1e5,可以分块。

我们预处理出这么两个数组。

一个是某个数字出现次数的分块前缀和,这个很简单。

一个是sum[ i ][ j ]代表从第i个分块到第j个分块出现次数为正偶数的数字的个数。

这个数组很好维护,只需要枚举左端点分块和右端点分块然后统计数字出现次数即可。

这些代码里有一些细节,可以结合注释理解。

for(int i=1;i<=get_pos(n);i++){
        int kin=0;
        for(int j=i;j<=get_pos(n);j++){          
            for(int k=(j-1)*len+1;k<=min(n,j*len);k++){//这里有一些细节
                tmp[a[k]]++;
                if((tmp[a[k]]&1))//如果这个数加完之后变成了奇数
                    if(tmp[a[k]]>1)//如果加完之后出现次数大于一,那么这个数就作为正偶数被统计进答案了,要减掉
                        kin--;
                    else//否则这个数在加一之前没有被统计过,没有必要更改,这里写个else是因为防止与下面那个else产生冲突
                        kin+=0;
                else//加完之后如果变成了偶数那肯定从奇数变成了正偶数,对答案有贡献
                    kin++;
            }
            sum[i][j]=kin;
        }
        for(int j=1;j<=c;j++)//清空辅助数组
            tmp[j]=0;
            
    }

接下来处理询问。

对于询问的l,r,算出其所在的分块lb,rb。

若l,r所在分块相同或相邻则暴力计算,时间复杂度n1/2

若l,r所在分块之间相隔至少一个分块,那么先将答案设成这两个分块之间的出现次数为正偶数的数字数量。

然后,计算两边散块内数字对答案的贡献。

情况较多,可结合注释理解。

void get_q(){
    ans=0;
    for(int i=l;i<=lb*len;i++){     
        tmp[a[i]]++;
        if(tmp[a[i]]&1)//如果这个数在散块中出现次数为奇数
            if((tim[rb-1][a[i]]-tim[lb][a[i]])&1)//如果它在中间块中出现次数为奇数,那么它没有被预先统计进答案里,且目前它对答案有贡献
                ans++;
            else//如果这个数在中间块中出现次数为偶数
                if(tim[rb-1][a[i]]-tim[lb][a[i]]>0)//如果这个数在中间块中出现次数为正偶数,那么它已经作为答案被统计过了,现在不符合条件要减掉
                    ans--;
                else//这个数并没有作为答案被统计过
                    if(tmp[a[i]]>1)//如果这个数在散块中之前已经作为正偶数被统计了,要减掉
                        ans--;
                    else//否则并没有影响
                        ans-=0;
        else//这个数在散块中出现次数为偶数
            if(tim[rb-1][a[i]]-tim[lb][a[i]]&1)//如果这个数在中间块中出现次数为奇数,那么这个数的出现次数被作为正偶数统计过,要减掉
                ans--;
            else//否则这个数之前没有算进答案里,要加进去
                ans++;
    }
    for(int i=(rb-1)*len+1;i<=r;i++){//以下分类同上
        tmp[a[i]]++;
        if(tmp[a[i]]&1)
            if((tim[rb-1][a[i]]-tim[lb][a[i]])&1)
                ans++;
            else
                if(tim[rb-1][a[i]]-tim[lb][a[i]]>0)
                    ans--;
                else
                    if(tmp[a[i]]>1)
                        ans--;
                    else
                        ans-=0;
        else
            if(tim[rb-1][a[i]]-tim[lb][a[i]]&1)
                ans--;
            else
                ans++;
    }
    for(int i=l;i<=lb*len;i++)//清空辅助数组
        tmp[a[i]]--;
    for(int i=(rb-1)*len+1;i<=r;i++)
        tmp[a[i]]--;  
    ans+=sum[lb+1][rb-1];
}

处理单次询问时间复杂度为n1/2,可以通过本题。

#include<bits/stdc++.h>
using namespace std;
const int h=100010;
const int b_h=1010; 
int n,m,c;
int len;
int a[h];
int sum[b_h][b_h];
int tim[b_h][h];
int tmp[h];
int get_pos(int x){
    return (x-1)/len+1;
}
void get_pre(){
    for(int i=1;i<=get_pos(n);i++)
        for(int j=1;j<=c;j++)
            tim[i][j]+=tim[i-1][j];
    for(int i=1;i<=get_pos(n);i++){
        int kin=0;
        for(int j=i;j<=get_pos(n);j++){          
            for(int k=(j-1)*len+1;k<=min(n,j*len);k++){
                tmp[a[k]]++;
                if((tmp[a[k]]&1))  
                    if(tmp[a[k]]>1)
                        kin--;
                    else
                        kin+=0;
                else
                    kin++;
            }
            sum[i][j]=kin;
        }
        for(int j=1;j<=c;j++)
            tmp[j]=0;
            
    }
}
int l,r,lb,rb;
int ans;
void get_vio(){
    ans=0;
    for(int i=l;i<=r;i++){
        tmp[a[i]]++;
        if((tmp[a[i]]&1))  
            if(tmp[a[i]]>1)
                ans--;
            else
                ans+=0;
        else
            ans++;
    }  
    for(int i=l;i<=r;i++)
        tmp[a[i]]--;   
}
void get_q(){
    ans=0;
    for(int i=l;i<=lb*len;i++){     
        tmp[a[i]]++;
        if(tmp[a[i]]&1)
            if((tim[rb-1][a[i]]-tim[lb][a[i]])&1)
                ans++;
            else
                if(tim[rb-1][a[i]]-tim[lb][a[i]]>0)
                    ans--;
                else
                    if(tmp[a[i]]>1)
                        ans--;
                    else
                        ans-=0;
        else
            if(tim[rb-1][a[i]]-tim[lb][a[i]]&1)
                ans--;
            else
                ans++;
    }
    for(int i=(rb-1)*len+1;i<=r;i++){
        tmp[a[i]]++;
        if(tmp[a[i]]&1)
            if((tim[rb-1][a[i]]-tim[lb][a[i]])&1)
                ans++;
            else
                if(tim[rb-1][a[i]]-tim[lb][a[i]]>0)
                    ans--;
                else
                    if(tmp[a[i]]>1)
                        ans--;
                    else
                        ans-=0;
        else
            if(tim[rb-1][a[i]]-tim[lb][a[i]]&1)
                ans--;
            else
                ans++;
    }
    for(int i=l;i<=lb*len;i++)
        tmp[a[i]]--;
    for(int i=(rb-1)*len+1;i<=r;i++)
        tmp[a[i]]--;  
    ans+=sum[lb+1][rb-1];
}
int main(){
    scanf("%d%d%d",&n,&c,&m);
    len=sqrt(n);
    for(int i=1;i<=n;i++)
        scanf("%d",&a[i]),tim[get_pos(i)][a[i]]++;
    get_pre();
    int lst=0;
    for(int i=1;i<=m;i++){
        scanf("%d%d",&l,&r);
        l=(l+lst)%n+1,r=(r+lst)%n+1;
        if(l>r)
            swap(l,r);
        lb=get_pos(l),rb=get_pos(r);
        if(lb>=rb-1)
            get_vio();
        else
            get_q();
        lst=ans;
        printf("%d\n",ans);
    }
    return 0;
}
完整代码

 

标签:tim,洛谷,分块,int,题解,else,--,ans,P4135
From: https://www.cnblogs.com/12103h/p/16884473.html

相关文章

  • 洛谷刷题_P217 [USACO1.5]回文质数 Prime Palindromes
    题目P217[USACO1.5]回文质数PrimePalindromes题目链接https://www.luogu.com.cn/problem/P1217知识点埃氏筛原理:要得到自然数n以内的全部素数,必须把不大于根号n......
  • 洛谷P4168 蒲公英 分块处理区间众数模板
    题面。许久以前我还不怎么去机房的时候,一位大佬好像一直在做这道题,他称这道题目为“大分块”。其实这道题目的思想不只可以用于处理区间众数,还可以处理很多区间数值相关......
  • 洛谷P7223 [RC-04] 01 背包
    [RC-04]01背包题目描述P7223[RC-04]01背包-洛谷有一个容积为正无穷的背包,你要往里面放物品。你有\(n\)个物品,第\(i\)个体积为\(a_i\)。你有一个幸运数......
  • 题解 P5188 【[COCI2009-2010#4] PALACINKE】
    postedon2022-07-2520:12:26|under题解|source做法:矩阵优化DP+容斥原理。矩阵优化DP先不要考虑商品,写个不管约束条件的DP。令\(f_{t,u}\)表示在\(t\)......
  • 题解 ABC270G【Sequence in mod P】
    postedon2022-10-2013:58:54|under题解|source有个地方写错了,改一下problemSoso有一个无穷序列\(\{X_i\}\)定义如下:\[X_i=\begin{cases}S,&(i=0)\\(A\cdo......
  • 20221112 - Find Device closed unexpectedly 问题解决
    问题现象:小米手机屏幕下方每隔2秒弹出 FindDeviceclosedunexpectedly问题解决:备份数据;并恢复出厂设置(开机前,按住音量键上或下+开机键)。备注:也尝试了一些网上的说法......
  • 「题解」Codeforces 1342F Make It Ascending
    只会\(\mathcal{O}(3^nn^2)\),打开题解一看怎么还真是这个玩意/jy首先集合之间形成一个sum和pos的二维偏序,那么思路就是对一维扫描线,然后另一维搞个什么东西。具体到......
  • 牛客小白月赛60 题解
    比赛通道:牛客小白月赛60前言第二次小白月赛没有AK,感觉自己可以原地退役了QAQ。这次F题理论上我能做出来,但是由于没有打表状态不佳,导致没有AK。A.小竹与妈妈思路这题......
  • 2022/11/11 集训题解
    今天是双11又是疯狂星期四,所以vivo50。比赛链接T2Description给出\(n\)个点\(m\)条边的图,问有多少种边的子集使得全图是个联通的仙人掌。答案对\(998244353\)取......
  • P3167 [CQOI2014]通配符匹配 题解
    想了两种做法,第一种拿到了10分的好成绩。而第二种做法不用前缀和,而且还跑的飞快。目前最优解第三尝试卡进最优解未果。不得不说这是一道好题,做完对KMP有了更深的理解......