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

 

posted @ 2017-12-09 12:37  Billyshuai  阅读(298)  评论(0编辑  收藏  举报