求调下午的 C
  • 板块学术版
  • 楼主wzzzh
  • 当前回复10
  • 已保存回复10
  • 发布时间2023/7/8 21:53
  • 上次更新2023/11/3 10:59:20
查看原帖
求调下午的 C
125428
wzzzh楼主2023/7/8 21:53
/** 关于使用的算法
 *  先将序列 A 和 B 中相同的数作一组存储(见 31 至 46 行)
 *  然后采用类似 KMP 的做法,不同的是计算前缀函数时计算相似的最长真前缀和真后缀的长度
 *  由于第一和最后一个数可能不会完全用到,因此对其单独处理
 */
#include<cstdio>
long long tmpn,tmpm;
int tmpa[5000005],tmpb[5000005];
long long n,m,cnt;
struct Data{
    int num;
    int cnt;
}a[5000005],b[5000005],sc[10000010];
long long pi[10000010],res;
int gcd(int __a,int __b){
    if(__b==0){
        return __a;
    }
    return gcd(__b,__a%__b);
}
long long min(const long long &__x,const long long &__y){
    if(__x<__y){
        return __x;
    }
    return __y;
}
int main(){
    scanf("%lld%lld",&tmpn,&tmpm);  // 读入数据
    a[0].num=0x7fff;
    b[0].num=0x7fff;
    for(long long i=1;i<=tmpn;i++){  // 整理
        scanf("%d",&tmpa[i]);
        if(tmpa[i]!=a[n].num){
            n++;
            a[n].num=tmpa[i];
        }
        a[n].cnt++;
    }
    for(long long i=1;i<=tmpm;i++){
        scanf("%d",&tmpb[i]);
        if(tmpb[i]!=b[m].num){
            m++;
            b[m].num=tmpb[i];
        }
        b[m].cnt++;
    }
    if(m==1){  // 特判特殊性质 A
        for(long long i=1;i<=n;i++){
            if(a[i].num==b[1].num){
                res+=((long long)a[i].cnt+1ll)*(long long)a[i].cnt/2ll;
            }
        }
        printf("%lld\n",res);
        return 0;
    }
    if(m==2){  // 特判特殊性质 B
        int g=gcd(b[1].cnt,b[2].cnt);
        b[1].cnt/=g;
        b[2].cnt/=g;
        for(long long i=1;i<n;i++){
            if(a[i].num==b[1].num&&a[i+1].num==b[2].num){
                res+=min((long long)a[i].cnt/(long long)b[1].cnt,(long long)a[i+1].cnt/(long long)b[2].cnt);
            }
        }
        printf("%lld\n",res);
        return 0;
    }
    for(int i=2;i<m;i++){  // 将序列 b 和 a 接到一起
        cnt++;
        sc[cnt]=b[i];
    }
    cnt++;
    sc[cnt].num=0x7fff;
    sc[cnt].cnt=0;
    for(int i=1;i<=n;i++){
        cnt++;
        sc[cnt]=a[i];
    }
    for(int i=2;i<=n+m-1;i++){  // 计算前缀函数(pi)
        int j=pi[i-1];
        while(j>0&&
              !(sc[i].num==sc[j+1].num&&
                (j+1==1||(long long)sc[i].cnt*(long long)sc[j].cnt==(long long)sc[i-1].cnt*(long long)sc[j+1].cnt))){  // 保证加入时比例相同
            j=pi[j-1];
        }
        if(sc[i].num==sc[j+1].num&&
           (j+1==1||(long long)sc[i].cnt*(long long)sc[j].cnt==(long long)sc[i-1].cnt*(long long)sc[j+1].cnt)){  // 保证加入时比例相同
            j++;
        }
        pi[i]=j;
        if(pi[i]==m-2){  // 由于将 b 和 a 接到一起时去掉了第一和最后一个元素,当 pi[i]==m-2 时即为匹配
            if(  // 判断去掉的两个元素是否匹配
                (i-pi[i]>=m&&i+1<=n+m-1)&&  // 避免越界
                (sc[i-pi[i]].num==b[1].num&&sc[i+1].num==b[m].num)&&  // 判断数值相同
                ((long long)sc[i-pi[i]+1].cnt*(long long)b[1].cnt/(long long)b[2].cnt<=(long long)sc[i-pi[i]].cnt&&  // 判断去除的元素是否足够以匹配
                 (long long)sc[i].cnt*(long long)b[m].cnt/(long long)b[m-1].cnt<=(long long)sc[i+1].cnt)&&
                (((long long)sc[i-pi[i]+1].cnt*(long long)b[1].cnt)%(long long)b[2].cnt==0ll&&  // 判断匹配是否为整数
                 ((long long)sc[i].cnt*(long long)b[m].cnt)%(long long)b[m-1].cnt==0ll)
            ){
                res++;
            }
        }
    }
    printf("%lld\n",res);
    return 0;
}
2023/7/8 21:53
加载中...