奋斗群群赛—5
T1:Curriculum Vitae
题目位置:
题意:
给你一个 0 1串,让你求出要删除多少的0或1 之后字符串变为前面都是0,后面都是1 的字符串?求出最大长度是多少?
AC代码:
#include <bits/stdc++.h>
using namespace std;
int a[105];
int main()
{
int n,tot=0;
cin>>n;
for(int i=1; i<=n; i++)
cin>>a[i];
for(int i=1; i<=n; i++)
{
{
int num=0,num0=0;
for(int j=i; j<=n; j++)
if(a[j]==1)
num++;
for(int j=1; j<=i; j++)
if(a[j]==0)
num0++;
if(num0+num>tot) tot=num0+num;
}
//else tot++;
}
cout<<tot<<endl;
}
小反思:
即知道如果在某个点时记录了1进去,那么之后只会有1出现,不会有别的数出现啊!
所以可以1~n的i 然后头到i 到尾再判一次!
T2:Math Show
题目位置:
题意:
有n个任务,每个都有k个子任务,完成第kj个子任务的时间为 ti,完成一个子任务得一分,而且完成了一个大任务则多得一分,让你求怎么做任务,让最后得到的点数变为最大,输出最大的值(贪心)!
AC代码:
#include <iostream>
#include <algorithm>
using namespace std;
const int N=50;
int time[N];
int main()
{
int n,k,t,all=0,tot=0;
cin>>n>>k>>t;
for(int i=1; i<=k; i++)
{
cin>>time[i];
all+=time[i];
}
sort(time+1,time+1+k);
for(int i=0; i<=n; i++)
{
int m=t-i*all,ans=0;//±íʾ×öÁË 0~n µÄ´óÈÎÎñ m ΪʣϵÄʱ¼ä
if(m<0) break;
ans+=i*k+i;
//cout<<ans<<" "<<m<<endl;
for(int v=1; v<=k; v++) //1~k µÄСÈÎÎñ ¿ªÊ¼½øÐÐÈûÂú
for(int j=1; j<=n; j++)
{
if(j+i<=n&&m>=time[v])
{
ans++;
m-=time[v];
}
if(j+i>n) break;
if(m<time[v])
break;
}
if(ans>tot)tot=ans;
}
cout<<tot<<endl;
}
小反思:
利用一个循环,从1~n个大任务循环,做完i个任务之后就专心做小任务就好,输出了最大的情况来!
T3:Four Segments
题目位置:
题意:
给了你n个数字a1~n.在有3个整数delim0,delim1,delim2,将这一行的数据分成4份,可以分别记为区间 s1,s2,s3,s4.求s1-s2+s3-s4的最大值的代表数字delim0,delim1,delim2的值,只要输出一个就好了!
但是记住比如区间s的算法是sum(l,r) 从l加到r但是不包括r,包括了l!
AC代码:
#include <bits/stdc++.h>
using namespace std;
const int N=5005;
long long int a[N],s[N];
int main() {
int n;
scanf("%d",&n);
long long int all=0;
for(int i=0; i<n; i++) {
cin>>a[i];
all+=abs(a[i]);
}
s[0]=0;
for(int i=1; i<=n; i++)
s[i]=s[i-1]+a[i-1];
long long int res=-9999999,delim0=-1,delim1=-1,delim2=-1;
for(int i=0; i<=n; i++) {
int d1,d2,d3;
d2=i;
d1=d3=d2;
for(int j=0; j<=i; j++) if(s[j]>s[d1]) d1=j;
for(int v=i; v<=n; v++) if(s[v]>s[d3]) d3=v;
long long int tot;
tot=s[d1]+s[d3]-s[d2];
if(tot>res) {
//cout<<s[i]<<" "<<s[j]<<" "<<s[v]<<" "<<s[n]<<endl;
res=tot;
delim0=d1;
delim1=d2;
delim2=d3;
}
}
cout<<delim0<<" "<<delim1<<" "<<delim2<<endl;
//cout<<res<<endl;
return 0;
}
小反思:
一开始就是开始算三重循环的算法来!结果会TLE哦,不过是一部成功的开始—所以将算法简化一点就是加上s[d1]+s[d3]-s[d2]的最大值,所以只要一个循环找s2,在从中找s1的max与s3的max就好了,然后看看能不能更新答案就好了!
T6:Random Query
题目位置:
题意:
给出一个n个数字的数列a[1],…,a[n],f(l,r)表示使a[l],a[l+1],…,a[r]组成的新序列中的重复元素只保留一个后,剩下元素的数量(如果l>r,则在计算前先交换l和r)。从1-n中分别选出两个数字l和r(两个数字选时各自独立,每个数字选出1-n的概率相等),求f(l,r)的数学期望。
AC代码:
#include <bits/stdc++.h>
using namespace std;
int head[1111111]= {0};
int main()
{
int n,x;
cin>>n;
long long int tot=-n;
for(int i=1; i<=n; i++)
{
cin>>x;
tot+=(long long int)(i-head[x])*(n-i+1)*2;
head[x]=i;
}
printf("%.10lf\n",(double)tot/((double)n*n));
}
小反思:
一定要推公式,不然又会TLE的!所以我们
就考虑当前这个数对多少区间有贡献,那么肯定是跨越它的区间了,我们可以从反面来考虑,假设每个数对所有区间都有贡献,那么贡献为n*n ,没有跨越它的区间就是他的左面和右面.我们要考虑减掉这一部分,但是如果有重复数的话,那么未出现该数的区间就是所有
重复数的两两中间那一部分了,其余的部分都出现了该数,该数都有价值.
head[i]记录上一个一样的数据的位置
(i-head[x])*(n-i+1)*2
总结
1.学会推公式
2.多考虑边界情况
3.灵活考虑剪枝的情况,可以方便不会TLE!
4.学会将三重循环转化为二重循环或者一重,只要发现之间的联系就好!