• Wannafly挑战赛5


    星神是来自宇宙的

    所以珂朵莉也是吧

    所以我就出了个题

    给你一个长为n的序列a,有n*(n+1)/2个子区间,问这些子区间里面和为完全平方数的子区间个数

    输入描述:

    第一行一个数n
    第二行n个数表示序列a

    输出描述:

    输出一个数表示答案

    示例1

    输入

    6
    0 1 0 9 1 0

    输出

    11

    1 <= n <= 100000

    0 <= ai <= 10

    数据范围一看就知道要枚举平方数了
    一开始我的思维是要找整好补全i^2的(0<=i<=1000)子区段,那么对于每个i^2,枚举起点为 j+1,然后用一个指针向后移动,当等于的时候退出并且加上,可以看出指针是不会向前移动的。所以维护的就是一个单指针,但是这样写。。。麻烦了

    看别人代码的思路是枚举每个可行区间的最后一个元素(显然有n个),做前缀和,所以说此时的前缀和a[j]肯定是大于等于可能满足的平方数喽,然后用a[j]-该平方数得到的数目就是要截去的数目,那么区间是连续的,所以只能是减掉某一个前缀和,所以记录过程中也只需要记录前缀和就OK了。

    #include<cstdio>
    #include<cstring>
    #include<string>
    #include<algorithm>
    using namespace std;
    const int N=1e5+88;
    int a[N];
    int ping[1008];
    void init(){
        for(int i=1;i<=1000;++i) ping[i]=i*i;
    }
    int b[N];
    inline int read()
    {
        int X=0,w=0; char ch=0;
        while(!isdigit(ch)) {w|=ch=='-';ch=getchar();}
        while(isdigit(ch)) X=(X<<3)+(X<<1)+(ch^48),ch=getchar();
        return w?-X:X;
    }
    int main(){
        int n;
        init();
        long long ans=0;
        scanf("%d",&n);
        for(int i=1;i<=n;++i) a[i]=read(),b[i]=1;
        int now=0;
        for(int i=n;i>=1;--i) {b[i]+=now;if(!a[i]) ++now; else now=0;}
        for(int i=1;i<=n;++i) a[i]+=a[i-1];
        for(int i=0;ping[i]<=a[n]&&i<=1000;++i) {
            int l=0;
            for(int j=0;j<n;++j) {
                if(j>=l) l=j+1;
                while(l<=n&&a[l]<a[j]+ping[i]) ++l;
                if(l>n) break;
                if(a[l]>a[j]+ping[i]) continue;
                ans+=b[l];
            }
        }
        printf("%lld
    ",ans);
    }
     1 #include <bits/stdc++.h>
     2 #define ll long long
     3 using namespace std;
     4 ll ans=0;
     5 int n,a[100005],s[100005];
     6 int num[1000005];
     7 int main (){
     8 int i,j;
     9 scanf ("%d",&n);
    10 num[0]++;
    11 for (i=1;i<=n;i++)
    12 {scanf ("%d",&a[i]);
    13 s[i]=s[i-1]+a[i];
    14 for (j=0;j*j<=s[i];j++)
    15 {ans+=num[s[i]-j*j];}
    16 num[s[i]]++;
    17 }
    18 cout<<ans<<endl;
    19 return 0;
    20 }

    题目描述

    给定一个小写字母字符串T

    求有多少长度为m的小写字母字符串S满足,T是S的一个子序列(不需要连续)

    输入描述:

    第一行一个字符串T
    第二行一个正整数m

    输出描述:

    输出答案对10
    9
    +7取模的值
    示例1

    输入

    a
    2

    输出

    51

    说明

    长度为2的里面有a的串有51种

    备注:

    1<=|T|,m<=10^5

    这个就是枚举最后一个字符所在的位置,然后其之前的空白处只能填 与他相邻的后一个规定字符不同的 字符就是25种,而最后一个字符之后的可以26种任意填。

    就是____a____b____c____ 第一二三段中的空白处有25*25*25种填法,c之后的有26种填发。
    要证明的就是这种算法是不重不漏的。
    不重的话:首先规定了枚举最后一个字符的位置,那么他之前的是不可能跟他一样了,因为倒数第一个可填的区间内(就是上面的第三段)是不可能填最后一个规定字符的,而倒数第二个区间段不可能填
    倒数第二个。。。依次类推,那么肯定是不重的了。
    不漏:具体代码里的枚举方法应该能保证不漏,具体怎么说也不太清楚。
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    const int N=1e5+88;
    const long long mod=1e9+7;
    long long fac[N];
    long long quick(long long n,long long k){
        long long ans=1;
        while(k){
            if(k&1) ans=(ans*n)%mod,k|=1;
            k>>=1;
            n=(n*n)%mod;
        }
        return ans;
    }
    long long C(long long n,long long m){
        return fac[n]*quick(fac[m],mod-2)%mod*quick(fac[n-m],mod-2)%mod;
    }
    char str[N];
    int main(){
        fac[0]=1;
        long long n,ans=0; 
        scanf("%s",str);
        scanf("%lld",&n);
        for(long long i=1;i<=n;++i) fac[i]=i*fac[i-1]%mod;
        long long m=strlen(str);
        for(long long i=m;i<=n;++i) ans=(ans+C(i-1,m-1)*quick(25,i-m)%mod*quick(26,n-i)%mod)%mod;
        printf("%lld
    ",ans);
    }
  • 相关阅读:
    移动端开发-禁止横屏
    奇葩的对象创建方式(更新中)
    每日积累之8.8
    每日积累 8.6
    折半查找
    linux中的amount的解释
    Redis集群错误
    每日积累 8.6
    Redis中在程序中的应用
    每日积累 8.4
  • 原文地址:https://www.cnblogs.com/mfys/p/8011164.html
Copyright © 2020-2023  润新知