【比赛报告】牛客NOIP暑期七天营-普及组1 报告
T1
T1难度并不高,只不过是开一个数组存储罢了,水题。
开一个num[]
数组,每次遇到一个字符时,把对应的“桶”加一便可以轻松拿到满分。
代码
#include <bits/stdc++.h> using namespace std; int num[200]; int main() { string s; int len; scanf("%d",&len); cin>>s; for(int i=0;i<len;++i) num[s[i]]++; for(int i='a';i<='z';++i) printf("%d ",num[i]); printf("\n"); }
T2
T2照理来说应该是一道模拟的暴力题。
然鹅…… 粗心的作者脑子发昏的写了一段代码:
#include <bits/stdc++.h> using namespace std; int main() { int n,m; string s; scanf("%d%d",&n,&m); cin>>s; string t,q; int len,f,ans=0; while(m--) { ans=0; cin>>q; len=q.length(); t=s; for(int i=0;i<len;++i) { f=t.find_first_of(q[i]); if(f==-1) continue; t=t.substr(f); ans++; } printf("%d\n",ans); } }
虽然跑得飞快(好像最慢的点也跑了50ms)。
but 答案错误 30
但这段代码没有考虑一种情况:
5
abcde
aebcd
对于这组数据,答案应该是4,取a,b,c,d
;
然而上面的这段程序运行时则会输出2,因为上面的程序会直接取e
,而放弃选择后边的b,c,d
,但显然,当然是选b,c,d
才是正解。
所以…… 让我们快(chui)快(tou)乐(sang)乐(qi)地写模拟吧~~~。
官方题解
对于,直接按题目模拟就好。每次两个指针扫一下就是
的了。整个加起来是
的复杂度。可以结合代码理解。
官方代码
#include <bits/stdc++.h> using namespace std; const int N=10100; int n,m; char s[N],t[N]; int main() { scanf("%d%d",&n,&m); scanf("%s",s+1); for(int i = 1; i <= m; ++i) { scanf("%s",t+1); int cur=1,len=strlen(t+1); for(int j=1;j<=n;++j) if(s[j]==t[cur]&&cur<=len) ++cur; printf("%d\n", cur-1); } }
T3
天哪!看到题目的第一眼就蒙了。
眼看一点思路都木有,于是,果断把“残缺的std”补全,拿到了10分。即使是现在,还是有点不理解……,顺便也吐槽一下,官方题解也写得太简单了吧!即使正常人看了都会蒙圈。
官方题解
对于直接copy代码然后完善一下头文件什么的就行了。
考虑这个是在干什么,其实就是求对于每个位置往前的前
大的数的和。
那么对于,直接删掉第三重循环(考虑如果不选这个数,可以直接直接从
转移,所以第三重循环完全多余)
对于,用一个数据结构动态维护前
大即可。(这里用
或者小根堆,都行)
复杂度
官方代码
#include <bits/stdc++.h> using namespace std; #define ll long long const int mod=1e9+7; const int N=1e6+10; int n,m,a[N]; int sum=0,ans=0; multiset<int> s; void inc(int &a, int b) { if(a>=mod) a-=mod; if(b>=mod) b-=mod; a+=b; if(a>=mod) a-=mod; if(a<0) a+=mod; } int main() { scanf("%d%d",&n,&m); for(int i=1;i<=n;++i) scanf("%d",&a[i]); for(int i=1;i<=m;++i) { s.insert(a[i]); inc(sum, a[i]); } inc(ans,sum); for(int i=m+1;i<=n;++i) { inc(sum,a[i]); s.insert(a[i]); int t=*s.begin(); inc(sum,-t); s.erase(s.begin()); inc(ans,sum); } printf("%d\n",ans); }
QwQ,完全看不懂在干哈子…… 55555……
T4
第四题画一个表格就知道了。
随机画一个表格,然后选择随便一块:
显然,绿***域的和为。
再选几块比较之后可知:
然后求出两个序列中的最大子串和一乘就是答案。
且慢……这题的数据范围有可能为,明显爆
int
,不开long long
见祖宗啊……
代码
#include <bits/stdc++.h> using namespace std; int a[100010],b[100010]; int maxsum(int arr[], int n) { int sum,maxx,i; maxx=0,sum=0; for(i=1;i<=n;i++) { sum+=arr[i]; if(sum>maxx) maxx=sum; else if(sum<0) sum=0; } return maxx; } int minsum(int arr[],int n) { int sum,minn,i; minn=0,sum=0; for(i=1;i<=n;i++) { sum+=arr[i]; if(sum<minn) minn=sum; else if(sum>0) sum=0; } return minn; } int minarr(int arr[],int n) { int ret=99999999; for(int i=1;i<=n;++i) if(abs(arr[i])<abs(ret)) ret=arr[i]; return ret; } int main() { int n,m; scanf("%d%d",&n,&m); for(int i=1;i<=n;++i) scanf("%d",&a[i]); for(int j=1;j<=m;++j) scanf("%d",&b[j]); int maxa,maxb; maxa=maxsum(a,n); maxb=maxsum(b,m); int mina,minb; mina=minsum(a,n); minb=minsum(b,m); long long ans; ans=((long long)(maxa))*((long long)(maxb)); ans=max(ans,((long long)(mina))*((long long)(minb))); if(ans==0) ans=minarr(a,n)*minarr(b,m); printf("%lld\n",ans); }