这次的校内训练有4题,难度适中,成绩也不错.令人诧异的是这次的四题居然都是原题.尽管如此,我还是有比较多的失误.
第一题原题在洛谷1360,网址:
题意大致是给出n个01串(不超过m位,压成整数)求这些串中最长的子串满足对于每一位,这个字串每个元素这位是1的个数的和相同.
比如:1110010 1001
1111001 1100
1010100 (竖着看从左往右7个整数)中有第3到第6个:1010 每一位1的个数都是2,所以满足
n<=100000,m<=30
那么,怎么解决呢?
凭感觉,我们前缀和一下,发现只要每行的某一位和另一位差为一个定值.进一步,我们考虑每行用和第一行的差距来代替,那么就等价于每行某一位和另一位相等,也就是找到完全相同的两列.
要找完全相同的距离最大的两列,就只要用stl的map或者哈希一下就好了.
囿于我不会写map(好好学习stl!)以及懒得打哈希,代码就不打了.考试时交了个暴力居然有70分,吐槽一下数据.
第二题原题NOIP2015跳石头,原题答案-1,百度一堆题解,这里就不赘述了.只是我只拿了30分,是四题中最低的,原因就是冒险用了不保险的二分方式导致死循环,一个字:浪!
代码如下:
#include#include int n,m,k,a[50002],l=0,r=1000000000,mid=(l+r)/2;bool check(int x){ int lst=0,cnt=0; for(int i=1;i<=n;i++)if((a[i]-a[lst])>x)lst=i,cnt++; return cnt>=n-k;}int main(){ scanf("%d%d%d",&m,&n,&k); for(int i=1;i<=n;i++)scanf("%d",&a[i]);a[++n]=m; std::sort(a+1,a+n+1); while(l >1; } printf("%d",mid-1); return 0;}
第三题题意是给定一堆任务,有限时和奖励,每单位时间只能做一个任务,求奖励最大值,据说是原题,反正不管他,比较水.
这题考场上随脑想了个贪心,就是从后往前扫时间,限时就变成了任务开启时间,然后直接按奖励贪心堆维护就好了
代码如下:
#include#include #include int a[100001],b[100001],o[100001],n,j=1;long long ans;std::priority_queue h;bool cmp(int x,int y){return a[x]>a[y];}int main(){ scanf("%d",&n); for(int i=1;i<=n;i++)scanf("%d%d",&a[i],&b[i]),o[i]=i; std::sort(o+1,o+n+1,cmp); for(int i=a[o[1]];i;i--) { for(;a[o[j]]==i;j++)h.push(b[o[j]]); if(!h.empty())ans+=h.top(),h.pop(); } printf("%lld",ans); return 0;}
但是正确性能保证,时间嘛...TLE了一个点,因为stl的pq实在是常数太大啦!我又开始想要不要学stl了...
第四题是裸的MST,直接按照图跑一遍就好了,而且数据范围很小,prim堆优化都不用开,kruskal因为边数太多更是浪费.轻松AC
代码:
#includeint a[301][301],n,val[301],ans;int main(){ scanf("%d",&n); for(int i=1;i<=n;i++)scanf("%d",&a[0][i]),a[i][0]=a[0][i]; for(int i=1;i<=n;i++)for(int j=1;j<=n;j++)scanf("%d",&a[i][j]); for(int i=1;i<=n;i++)val[i]=a[0][i]; for(int i=1;i<=n;i++) { int Min=-1; for(int j=1;j<=n;j++)if(val[j]!=0)if(Min==-1)Min=j;else if(val[Min]>val[j])Min=j; ans+=val[Min]; for(int j=1;j<=n;j++)val[j]=val[j]>a[Min][j]?a[Min][j]:val[j]; } printf("%d",ans); return 0;}
这场比赛还算是春风得意吧.才有时间迅速调完写完博.