• 总体感受
  • T1
    • 题目
    • 思路
  • T2
    • 题目
    • 思路
  • T3
    • 题目
    • 思路
  • T4
    • 题目
    • 思路
  • T5
    • 题目
    • 思路
  • T6
    • 题目
    • 思路

总体感受

https://cn.vjudge.net/contest/183919#overview
本次的6题非常非常难,前两题极坑,后面研究了好久完全没有规律,我连爆搜都不会写.
我在比赛中途已经发呆了一个多小时,现在离结束还有9分钟,我已经放弃了.

T1

题目

唯一一道勉强能A的题,输入一个只有0,1的数组,去掉一些数字,使得所有的1之后都没有0,求剩下的数字最多有多少.

思路

花了我2小时才想出了递推的方法.我先讲讲我研究了1小时的错误做法.
首先把数组中前面的0和后面的1加到ans里(肯定不用去掉),然后对于每一个1,0分割线,把前面1的数量和后面0的数量比较一下取较大数目.
问题在于,如果数据变大到100个,中间有的时候你并不能取1而只能取0,这个时候这个程序就挂了.错误代码如下.

#include<bits/stdc++.h>
using namespace std;
int a[102];
int main()
{
int n,i,j,k,s;
cin>>n;
for (i=0;i<=101;i++) a[i]=2;
for (i=1;i<=n;i++) cin>>a[i];
for (i=1;i<=n;i++) if (a[i]==1) break;
s=i-1;
for (i=n;i>=1;i--) if (a[i]==0) break;
s+=n-i-1;
for (i=1;i<=n-1;i++) if (a[i]==1&&a[i+1]==0){j=i;k=i+1;while (a[j]==1) j--;while (a[k]==0) k++;s+=max(k-i-1,i-j);}
cout<<s+1;
}

所以我知道这个题要递推.对于输入的第i个数,到它为止能取的最多的数字用s1表示,在它之前有的0的个数用s表示.那么对于每一个1,到它为止能取的一种方法是,取前面所有的0和它,或者取它前面的1时候的s.故可得到如果输入1则s1=max(s1+1,s+1);输入0则s+1.故代码实现如下,反而简单了很多.

#include<bits/stdc++.h>
using namespace std;
int a[102];
int main()
{
int n,i,s=0,s1=0;
cin>>n;
for (i=1;i<=n;i++){cin>>a[i];if (a[i]==1) s1=max(s+1,s1+1);else s++;  }
cout<<max(s,s1);
}

T2

题目

有m道一样的题目,每道题分成n个部分,每个部分想要解出需要a[i]点实力值,解出之后获得1分.如果你把一道题的n个部分全部解出,你能获得n+1分.已知你的实力值,求你能得到最大的分数.

思路

数据范围不大,O(n^3)的爆搜也不会超时,可是此题极坑!!!!!
很明显有两种搜法,第一种是一排一排做,每次做一整道题,直到剩余的实力值不能做一整道题再从头开始每次做花费最小的部分,直到用完实力值,计算结果;第二种是直接从头开始搜,一直做花费最小的,直到结束.
坑点在哪里?首先坑爹在即使你是用的第2种方法,你在搜到最后一个数值时做完之后要+1,因为你做完了一整道题!可是这样还没完!当你搜到倒数第二个数的时候,这时如果最后一个数和倒数第2个数一样,并且你还能再做一个部分,这时候你不能做下一题的倒数第2个部分,而是要做这题的最后一个部分,这样能多1分!当我知道最后一个坑点,我无能为力了.
这个代码用的是爆搜,由于数据范围小,就搞定了.

#include<bits/stdc++.h>
using namespace std;
long long a[50];
int main()
{long long m,n,i,j,k,l,answer=-100000;cin>>m>>n>>k;a[0]=0;for (i=1; i<=n; i++) cin>>a[i];sort(a,a+n+1);for (i=1; i<=n; i++) a[i]+=a[i-1];for (i=0; i<=n-1; i++) for (j=0; j<=m; j++) for (l=0; l<=m-j; l++) if (m*a[i]+j*(a[n]-a[i])+l*(a[i+1]-a[i])<=k)//大神解释一下这句话和下面这句的意思吧,我抄来了代码,看了好久也没看懂answer=max(answer,i*m+j*(n+1-i)+l);cout<<answer;
}

T3

题目

我们定义一个函数sum(i,j)表示从数组中的a[i]+a[i+1]+……+a[j-1].(i算,j不算)给出数组第一个的下标为0,找出其中三个分界点d1,d2,d3,使得sum(0,d1)-sum(d1,d2)+sum(d2,d3)-sum(d3,n)最大,输出其中一种结果。

思路

利用num数组计算前缀和,sum(d1,d2)=num[d2-1]-num[d1-1].
第一种方法O(n^3)时间复杂度,暴枚d2的所有位置,对于每一个位置,有0<=d1<=d2,d2<=d3<=n,在范围内暴枚d1和d3,肯定会TLE。
所以我这么想:计算式的结果等于2*num[d1-1]-2*num[d2-1]+2*num[d3-1]-num[n].
在比较时,同时减num[n]可以舍去,剩下的可以除以2。最后其实比较的很少,就是num[d1]-num[d2]+num[d3].
那么枚举的时候可以枚举num[d1]和num[d3]的最大值计算就可以了。

#include<bits/stdc++.h>
using namespace std;
long long a[5010]={0};
int main(){long long n,i,j,k,i1,j1,k1,maxi,maxj,maxk,sum=-2147483647;cin>>n;for (i=1; i<=n; i++) cin>>a[i];for (i=1; i<=n+1; i++) a[i]+=a[i-1];for (j=0; j<=n; j++){j1=j;i1=k1=j1;for (i=0; i<=j; i++){if (a[i]>=a[i1]) i1=i;//枚举a[i1]是最大值} for (k=j; k<=n; k++){if (a[k]>=a[k1]) k1=k;//同理} if (a[i1]+a[k1]-a[j1]>=sum){sum=a[i1]+a[k1]-a[j1];maxi=i1;maxj=j1;maxk=k1;}}cout<<maxi<<" "<<maxj<<" "<<maxk;}

T4

题目

恰好9月9日凌晨零点我A了这个题。一台已经老旧的电视机,每隔一个时间点,电视机的一个像素就会坏掉。我们认为电视机上坏掉的像素点能组成一个k*k的正方形,则电视机就坏了。输入电视机屏幕大小n,m和k,以及要坏掉的像素点个数q,以下每一个像素点的位置坐标和坏掉的时间,问多久之后电视机坏掉?若电视机在所有像素点坏掉之后都不会坏,输出“-1”。

思路

我在写的时候把电视机屏幕n和m输入反了,找了半个小时才找到错。首先我对所有像素点的时间进行排序。我一开始用的是冒泡排序,但是发现因为q<=250000,冒泡排序会炸,所以我花了好久手写了一个快排,结果在第16个点WA了。如何判断坏掉的点生成了一个正方形?在电视机中有(n-k+1)*(m-k+1)个k*k的正方形,我对每一个正方形的右下角标记,如下。

#include<bits/stdc++.h>
using namespace std;
int x[250010],y[250010],t[250010],broken[510][510]={0};
void qsort(int l,int r)
{
int i=l,j=r,mid=t[(l+r)/2];
if (l>r) return;
while (i<=j)
  {while (t[i]<mid) i++;while (t[j]>mid) j--;if (i<=j)
    {swap(x[i],x[j]);swap(y[i],y[j]);swap(t[i],t[j]);//快排同时交换x[i],y[i],t[i],故不能用sorti++;j--;}}
if (i<r) qsort(i,r);
if (j>l) qsort(l,j);
}
int main()
{
int n,m,k,p,i,j,l;
cin>>n>>m>>k>>p;
for (i=1;i<=p;i++) scanf("%d%d%d",&x[i],&y[i],&t[i]);
qsort(1,p);//快排
for (i=1;i<=p;i++)
for (j=x[i];j<=x[i]+k-1;j++)
for (l=y[i];l<=y[i]+k-1;l++)//暴枚每一个正方形的右下角,当该点坏掉时,存在该点的正方形右下角++{broken[j][l]++;if (broken[j][l]>=k*k) {cout<<t[i]; return 0;}}
cout<<-1;
}

这个代码的时间复杂度是O(q*k^2),数据一大还是会T。而且它在第16个点就WA了,我也无话可说了。所以我看了别人的代码,又手打了一遍,结果把n,m打反了,怎么样都输出-1。这个代码用的是二分法,把q变成了log(q),果然厉害。

#include<bits/stdc++.h>
using namespace std;
int a[510][510]={0},d[510][510]={0};
int main()
{
int m,n,k,q,x,y,t,i,j,l,r,result=-1,mid;
cin>>n>>m>>k>>q;
memset(a,63,sizeof(a));
for (i=1;i<=q;i++) {scanf("%d%d%d",&x,&y,&t);a[x][y]=t;}
l=0;r=1000000000;
while (l<=r)//二分法,通过枚举时间小于等于mid的点来估计到什么时候电视会坏。{mid=(l+r)/2;bool nico=0;memset(d,0,sizeof(d));for (i=1;i<=n;i++) for (j=1;j<=m;j++) {d[i][j]=1+min(d[i-1][j-1],min(d[i][j-1],d[i-1][j]));//如果左,上,左上三个点都不是0,则该点能继续算下去,否则就没有正方形了。if (a[i][j]>mid) d[i][j]=0;//排掉时间大于一半的点
    if (d[i][j]>=k) nico=1;
    }if (nico==1)
    {    result=mid;
    r=mid-1;
    }else l=mid+1;}
cout<<result;
}

T5

题目

你要做实验,实验室里有n种材料,每种材料数量为b[i],你需要的每种材料数量为a[i]。
你可以按照一定规律转化材料,输入n-1条数据x[i],k[i],表明k[i]单位的x[i]能够转化为1单位的i,同理,1单位的i能转化成1单位的x[i].输入以上数据,判断你是否能获得足够的材料来做此次实验,如果是,输出“YES”,否则输出”NO”.

思路

首先把a[i]-b[i],判断手上的材料与需要的材料的数量是多了还是少了。然后从后往前,如果材料多出来,把它转化为x[i] (只考虑1单位的i能转化成1单位的x[i]),否则用x[i]补上它,最后看看第一个是不是刚好或者多出来就可以了。

#include<bits/stdc++.h>
using namespace std;
double ans[100001];long long x[100001],k[100001];
int main()
{
int n,i;
cin>>n;
for (i=1;i<=n;i++) cin>>ans[i];
for (i=1;i<=n;i++) {long long a;cin>>a;ans[i]=a-ans[i];//负数是多出来的,正数是不足的}
for (i=2;i<=n;i++) cin>>x[i]>>k[i];
for (i=n;i>1;i--) {if (ans[i]>0) ans[x[i]]+=k[i]*ans[i];//少的按照系数k[i]往上补else ans[x[i]]+=ans[i];//多出来的直接转化}
if (ans[1]<0.5) cout<<"YES";//如果第一种材料刚好或多出来,当然就够了
else cout<<"NO";
}

T6

题目

给定一个数组,求随机选两个位置之间不同数字个数的期望值.

思路

对于不同位置,一共有n*n种选法.对于每两个位置选的时候有l,r和r,l两种可能,乘以2.重复的数字不进行计算.中间公式这里还是看不懂.

#include<bits/stdc++.h>
using namespace std;
int head[1111111]={0};
int main()
{
int n,x,i;
cin>>n;
long long int tot=-n;
for (i=1;i<=n;i++){cin>>x;tot+=(long long int)(i-head[x])*(n-i+1)*2;//看不懂head[x]=i;}
printf("%.10lf",(double)tot/((double)n*n));
}

奋斗群群赛5总结与心得相关推荐

  1. 奋斗群群赛2总结与心得

    T1 题目 思路 T2 题目 思路 T3 题目 思路 T4 题目 思路 T5 题目 思路 总结 https://cn.vjudge.net/contest/183263#overview T1 题目 ...

  2. 奋斗群群赛19总结与心得

    总体情况 T1 思路 T2 思路 T3 思路 T4 思路 T5 思路 总体情况 老师再一次对我们相当不友好,把比赛的A题换成了一道C题.今天我是真的爆零了,非常遗憾E本是一道非常水的并查集,我却WA了 ...

  3. 一篇关于数学建模美赛论文撰写的心得

    在数学建模比赛中,论文是队伍最终成果的呈现,也是评委评判获奖等级的唯一依据.因此,论文的重要性无须赘述. 最理想的情况是第一天上午确定选题阅读过相关论文之后,下午就开始写论文,最晚第二天早上必须开始写 ...

  4. 胖哈勃杯第十三届CUIT校赛web500wp及出题心得

    这大概是我搭建最大的环境吧,贴近实战.回路有点多,按ctf思路套路来做,还是有点麻烦. 总共用了7台服务器,虽然不需要这么多.但是还是怕搅?被穿. 前言 膜rr大佬,被rr大佬一直非预期,不过还是很开 ...

  5. 数学建模国赛经验分享

    CSDN话题挑战赛第1期 活动详情地址:https://marketing.csdn.net/p/bb5081d88a77db8d6ef45bb7b6ef3d7f 参赛话题:大学生竞赛指南 话题描述: ...

  6. 心得体会标题大全_给心得起个标题

    _百度知道 最佳答案: 心得体会的开头可以采用以下几种形式:在XX活动中的心得体会,关于XX活动心得体会(或心得).心得体会标题大全 - 豆丁网 2018年3月14日 - 心得体会标题大全第一篇_&l ...

  7. czl蒻蒟的OI之路14、15

    XJOI奋斗群蒻蒟群群赛15 RANK排名9 T1Fashion in Berland 已AC 题意 分析过程 给出题解 T2s-palindrome WA四次后AC 题意 分析过程 给出题解 T3E ...

  8. czl蒻蒟的OI之路

    XJOI奋斗群蒻蒟群群赛2 RANK排名3 T1Odds and Ends 已AC 题意 分析过程 给出题解 T2Tell Your World 已AC 题意 分析过程 给出题解 T3From Y t ...

  9. czl蒻蒟的OI之路5

    XJOI奋斗群蒻蒟群群赛6 RANK排名10 T1Fraction已AC 题意 分析过程 给出题解 T2Maxim Buys an Apartment WA两次AC 题意 分析过程 给出题解 T3Pl ...

最新文章

  1. Exchange 2010 移动邮箱时提示超过了目标配额
  2. linux shell 宏定义_Linux系统和Shell命令行简介,走上数据分析之路
  3. 【c语言】蓝桥杯算法训练 十进制数转八进制数
  4. Python 从入门到精通:一个月就够了!
  5. 全国首个海底数据中心落地三亚,拉开海洋新基建赋能低碳算力序幕
  6. Xshell的安装和连接
  7. excel 中的文本是ansi还是unicode_详细讲解Excel中常用的文本函数
  8. 可以用推理来过度分析《无穷动》
  9. python3 json_Python3 解析复杂结构的 json
  10. HTML5: 利用SVG动画动态绘制文字轮廓边框线条
  11. 指针运算符 * 说明
  12. (9)机器学习_多分类器OneVsRestClassifier
  13. 头文件交叉声明的解决办法
  14. kotlin android中文文档,Kotlin(android)协程中文翻译
  15. 华为服务器SNMP协议怎么修改,华为迈普交换机、瑞斯康达SNMP协议配置方法
  16. 使用Python自动下载Himawari-8(葵花8)数据产品——以AOD L3级日均数据和小时数据为例
  17. 这几款手机安全浏览器,好用不止一点点
  18. Java:每日获取稳定可用免费代理ip(仅供日常使用,请勿用作他途)
  19. Exploratory Social Network Analysis with Pajek(第三版)2-1
  20. VS2010运行DirectShow的错误—typedef void * POINTER_64 PVOID64

热门文章

  1. 【操作系统】Linux体系
  2. Linux任务之自动发邮件
  3. 5.从键盘接收一百分制成绩 (0~100)
  4. OpenResty LuaJIT和lua-resty-core(FFI vs Lua CFunction)介绍
  5. 高级测试工程师需要具备哪些能力?看完我悟了
  6. 北京科技大学通用学术英语作文Mooc 大一上(20级版)
  7. $(window).height() 和 $(document).height()的区别
  8. Cisco交换机划分内网Vlan
  9. 双高斯拟合,差距啊,继续努力吧!
  10. 模型量化(3):ONNX 模型的静态量化和动态量化