• 牛客NOIP暑期七天营-提高组5


    A:deco的abs 水题,先%,然后相邻两个数min()一下差值。

    #include<bits/stdc++.h>
    #define ll long long
    using namespace std;
    const int maxn=10000000;
    const int Mod=998244353;
    int a[maxn]; ll ans;
    int main()
    {
        int N,D;
        scanf("%d%d",&N,&D);
        for(int i=1;i<=N;i++) scanf("%d",&a[i]),a[i]%=D;
        for(int i=2;i<=N;i++) {
            int t=abs(a[i]-a[i-1]);
            ans+=min(t,D-t);
        }
        printf("%lld
    ",ans);
        return 0;
    }

    B:deco的gcd .给出数组a[],求两两gcd之积。

    当然如果是两两gcd之和,就是司空见惯的反演了。

    没做过的,可以参考:

          HDU - 4676 :Sum Of Gcd (莫队&区间gcd公式)      CodeForces - 645F:Cowslip Collections (组合数&&欧拉函数)

    1,但是这里是之积,就有点烦。 我们可以把乘法变为加法,然后反演。

    2,从另外一个角度看,由于是乘法,而且是积性函数,所以我们每个素数单独考虑。对于同一个素数p,其贡献是一个取min操作, 求出每个数有多少个p,然后基数统计一下前缀和,就可以算贡献了。  注意还要欧拉降幂(我忘了降幂GG了)。

    处理每个数的素数及其幂次;

    1,有根号算法,单词复杂度sqrt。

    2,预处理sqrt以内的素数,128个。单词复杂度128;

    3,素数筛的时候记录每个数的最小素数P[i]。那么可以一直除P[i],直到为1,复杂度<18;

    #include<bits/stdc++.h>
    #define rep(i,a,b) for(int i=a;i<=b;i++)
    using namespace std;
    const int maxn=1000010;
    const int Mod=998244353;
    int vis[maxn],p[maxn],cnt,ans=1,K,P[maxn];
    int qpow(int a,int x){
        int res=1; while(x){
            if(x&1) res=1LL*res*a%Mod;
            x>>=1; a=1LL*a*a%Mod;
        } return res;
    }
    void init()
    {
        for(int i=2;i<maxn;i++){
            if(!vis[i]) p[++cnt]=i,Mn[i]=Mod,P[i]=i;
            for(int j=1;j<=cnt&&i*p[j]<maxn;j++){
                vis[i*p[j]]=1; P[i*p[j]]=p[j];
                if(!(i%p[j]))  break;
            }
        }
    }
    int G[maxn][20];
    int main()
    {
        int N,Q,x;
        init();
        scanf("%d",&N);
        rep(i,1,N) {
            scanf("%d",&x);
            while(x>1){
                int t=P[x],res=0;
                while(x%t==0) x/=t,G[t][++res]++;
            }
        }
        rep(i,1,cnt){
            int sum=0;
            for(int j=1;j<=18;j++){
                int t=G[p[i]][j];
                if(t<=1) break;
                (sum+=1LL*t*(t-1)/2%(Mod-1))%=(Mod-1);
            }
            ans=1LL*ans*qpow(p[i],sum)%Mod;
        }
        printf("%d
    ",ans);
        return 0;
    }

    C:deco的str

    题意:S中每个位置的值val为对应区间=T的循环同构数,求相邻位置的val的积的和。

    思路:如何求每个位置的值,如果对S进行循环同构,复杂度会比较高。 所以考虑对T进行M次循环同构,生成了M个新的字符串{},记录每个新的字符串出现了多少次,然后每个位置的val=对应{}中字符串的出现次数。 那么显然可以hash来做,为了保险,可以用双hash。

    题解的思路: 考虑对S循环同构。  不难想到,对于一个pos,它做出贡献的形式是,S[pos+1...]+S[...pos]=T,所以我们求出每个pos和T的前缀匹配的最长公共前缀长度L[]。每个pos和T的最长后缀长度P[]。 那么pos的贡献应该是max(0,P[pos]+L[pos]-lenT); (大概是这样)。

    而求L,就是exKMP;  求P,就是把T倒序,S倒叙,再求一次exKMP即可。

    #include<bits/stdc++.h>
    #define ull unsigned long long
    #define rep(i,a,b) for(int i=a;i<=b;i++)
    using namespace std;
    const int maxn=10000010;
    const int Mod=1e9+7;
    int seed=131; ull p[maxn],h[maxn],fcy;
    char a[maxn],b[maxn]; int ans;
    unordered_map<ull,int>mp;
    ull gethash(int L,int R)
    {
        return h[R]-h[L-1]*p[R-L+1];
    }
    int main()
    {
        int N,M; scanf("%s%s",a+1,b+1);
        N=strlen(a+1); M=strlen(b+1);
        if(N<M*2) return puts("0"),0;
        p[0]=1; rep(i,1,N) p[i]=p[i-1]*seed;
        rep(i,1,N) h[i]=h[i-1]*seed+a[i]-'a'+1;
        rep(i,1,M) fcy=fcy*seed+b[i]-'a'+1;
        mp[fcy]++;
        rep(i,1,M) fcy=(fcy-(b[i]-'a'+1)*p[M-1])*seed+b[i]-'a'+1,mp[fcy]++;
        rep(i,1,N+1-M-M) {
            ull A=gethash(i,i+M-1),B=gethash(i+M,i+M+M-1);
            if(mp.find(A)==mp.end()) continue;
            if(mp.find(B)==mp.end()) continue;
            ans=ans+1LL*mp[A]*mp[B]%Mod;
            if(ans>=Mod) ans-=Mod;
        }
        printf("%d
    ",ans);
        return 0;
    }

     

  • 相关阅读:
    基于 IAR 修改工程名称
    Baidu IoT Study
    msp430f5438a Information Flash Seg Write -- Chapter
    MFC 编辑框内容更新方法以及滚动条设置
    通过打开按钮打开文件和通过左键移动打开文件并计算crc
    移动文件并将文件路径显示到编辑框内
    Aritronix Virtual Device 运行
    将一个char类型的数转换成曼切斯特数
    数组中重复的数字
    平衡二叉树
  • 原文地址:https://www.cnblogs.com/hua-dong/p/11404717.html
Copyright © 2020-2023  润新知