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
输出描述:
输出答案对109
+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); }