奋斗群群赛8总结与心得,附上周所有错误小结

来源:互联网 发布:mysql yum 安装 编辑:程序博客网 时间:2024/05/18 16:36

  • 总体情况
  • 上周小结
  • T1
    • 题目
    • 思路
  • T2
    • 题目
    • 思路
  • T3
    • 题目
    • 思路
  • T4
    • 题目
    • 思路
  • T5
    • 题目
    • 思路
  • T6
    • 题目
    • 思路

总体情况

本次题目暴枚较多,弄不好容易TLE,掌握方法即可.

上周小结

错误极多.最常见的是爆int,有的时候真的你在电脑上能好好运行,一放到评测机上就gg了.隐性的情况一定要注意了.还有当写for循环的时候修改循环变量一定要改全!三个字母都要改!for(int i=1;i<=n;i++)这句话里三个i都要改!我手残改了前面两个,运行出错,我怎么都找不到问题.重要的事情要说三遍!最后记得输入矩阵的时候n和m不要打反,也很难找出的错误,搞了我半小时.好好想想思考方法,总有办法的.

T1

题目

输入n和k,如果能找到k个不为1的数,它们相乘等于n,则输出这k个数(spj,一种方法);如果找不到,输出-1.

思路

暴枚+递归,从2开始找到n最小的因数i,找到之后把n/i继续操作,直到n为1还是没有k个数或者已经找到第k个数为止.

#include<bits/stdc++.h>using namespace std;int n,k,a[25];void fenjie(int n,int m)//m表示分解到第几个数{int i;if (n==1&&m<=k) {cout<<"-1";return;}//没有k个数else if (m==k)  {  for (i=1;i<=k-1;i++) cout<<a[i]<<" ";  cout<<n;  return;  }for (i=2;i<=n;i++) if (n%i==0)  {  a[m]=i;  fenjie(n/i,m+1);  break;  }}int main(){cin>>n>>k;fenjie(n,1);}

T2

题目

在一个数组中任意找k个数求和,和必须是奇数,输出最大的和.

思路

数组里是有负数的.首先把所有正数加起来,然后看看是不是奇数,如果不是奇数,就在所有的数里找到绝对值最小的奇数,把它减掉即可.

#include<bits/stdc++.h>using namespace std;int a[100010];int main(){int n,i,xiao=2147483647;long long he=0;//100000,100000的数据范围不能忘long longcin>>n;for (i=1;i<=n;i++)  {  scanf("%d",&a[i]);  if (a[i]>0) he+=a[i];  if (a[i]&1) xiao=min(xiao,abs(a[i]));  }  if (he&1) cout<<he;else cout<<he-xiao;}

T3

题目

给出一个小写英文字母组成的字符串,把里面所有的字符进行不断地入栈,出栈操作,输出这样操作出栈的字符串当中字典序最小的一个.

思路

最关键的一点是每次找最小的字符出栈.我用一个字符数组存储从尾到头最小的字符.然后对字符串入栈,当栈不为空并且栈顶字符小于或者等于当前最小字符,就让它出栈.

#include<bits/stdc++.h>using namespace std;stack<char> t;string s;char final[100010];int main(){int i,p=0;cin>>s;int l=s.size();final[l]=123;for (i=l-1;i>=0;i--) final[i]=min(final[i+1],s[i]);//把下面那句话不要注释掉观察一下,你会发现原因,这个字符串就是把比较小的字符位置卡住,不让比它大的字符先出栈.//cout<<final<<endl;while (t.empty()==0||p<l)  {  while (t.empty()==0&&t.top()<=final[p])//必须等到最小字符全部出栈才能继续第二小字符,同时final[p]此时就会变成第二小字符了.    {    printf("%c",t.top());    t.pop();    }   if (p==l) break;  t.push(s[p]);  p++;  }}

T4

题目

对于一棵二叉查找树来讲,你一定能用下面这样的代码查找到每一个值.

bool find(TreeNode t, int x) {
if (t == null)
return false;
if (t.value == x)
return true;
if (x < t.value)
return find(t.left, x);
else
return find(t.right, x);
}
find(root, x);
可是不是所有的数都是二叉查找树,输入一棵树的所有结点以及其子节点情况(没有输入-1),输出用上述查找方法查找失败的次数.

思路

dfs,代码放在下面,但是不会思路.

#include<bits/stdc++.h>using namespace std;int n,x[100010],l[100010],r[100010],answer=0;bool visible[100010];set<int> node_visible;void searching_mistakes(int root,int left,int right){if (x[root]>=left&&x[root]<=right) node_visible.insert(x[root]);if (l[root]!=-1) searching_mistakes(l[root],left,min(right,x[root]-1));if (r[root]!=-1) searching_mistakes(r[root],max(left,x[root]+1),right);}int main(){int i;cin>>n;for (i=1;i<=n;i++)  {  scanf("%d%d%d",&x[i],&l[i],&r[i]);  if (l[i]!=-1) visible[l[i]]=1;  if (r[i]!=-1) visible[r[i]]=1;  }for (i=1;i<=n;i++) if (visible[i]==0) searching_mistakes(i,0,2147483647);for (i=1;i<=n;i++) if (node_visible.find(x[i])==node_visible.end()) answer++;cout<<answer; }

T5

题目

输入一个数组a[n],以下q个询问,每个询问有p,k两个值,对于每个询问每次让p=p+a[p]+k,直到p>n为止,输出操作次数.

思路

这题肯定是暴枚了.

#include<bits/stdc++.h>using namespace std;int a[100010],p,k;int main(){int n,i,q;cin>>n;for (i=1;i<=n;i++) scanf("%d",&a[i]);cin>>q;for (i=1;i<=q;i++)   {  scanf("%d%d",&p,&k);  int t=0;  while (p<=n)    {    p+=a[p]+k;    t++;     }   printf("%d\n",t);  }}

TLE了.我们可以用什么方法来存储呢?我们可以定义一个二维数组large_master[p][k],让large_master[p][k]存储询问p,k的值.如果这个值已经有了,我们就可以直接输出;如果没有,我们就定义一个dfs,返回dfs(p+a[p]+k,k)+1.你问我数组的大小要炸啊!用空间换时间没有必要这么彻底,我们可以存储到sqrt(n)为止.我故意把函数名,数组名定义得很长,看起来好像我写了很多.可以把时间复杂度缩到n*sqrt(n).

#include<bits/stdc++.h>using namespace std;int a[100010],n,q,p,k,large_master[100010][400],pingfanggen;int addpoints(int p,int k){if (p>n) return 0;if (k<=pingfanggen&&large_master[p][k]!=0) return large_master[p][k];if (k<=pingfanggen) return large_master[p][k]=addpoints(p+a[p]+k,k)+1;return addpoints(p+a[p]+k,k)+1;}int main(){int i;cin>>n;for (i=1;i<=n;i++) scanf("%d",&a[i]);cin>>q;pingfanggen=round(sqrt(n));for (i=1;i<=q;i++)   {  scanf("%d%d",&p,&k);  printf("%d\n",addpoints(p,k));  }}

T6

题目

一条线上有很多老鼠,有很多老鼠洞.突然老鼠们受到了惊吓,纷纷逃回洞.每个洞有自己能够装下老鼠的最大个数,输入每个老鼠的坐标,洞的坐标以及洞的最大安放数,输出老鼠逃回洞最少要走的距离.

思路

不要问我思路.

#include<bits/stdc++.h>using namespace std;typedef long long ll;const ll boss=5000;struct hole{int p,c;}h[boss+10];int x[boss+10],q[boss+10],l,r;ll dp[boss+10][boss+10],s[boss+10];bool cmp(hole a,hole b){return a.p<b.p;}int main(){int n,m,i,j;ll counting=0;cin>>n>>m;for (i=1;i<=n;i++) scanf("%d",&x[i]);for (i=1;i<=m;i++) scanf("%d%d",&h[i].p,&h[i].c),counting+=h[i].c;if (counting<n) return printf("-1"),0;sort(x+1,x+n+1);sort(h+1,h+m+1,cmp);memset(dp,0x3f,sizeof(dp));dp[0][0]=0;for (i=1;i<=m;i++) for (q[l=1,r=0]=j=0;j<=n;j++)  {  s[j]=s[j-1]+abs(h[i].p-x[j]);  while (l<=r&&dp[i-1][j]-s[j]<=dp[i-1][q[r]]-s[q[r]]) r--;  q[++r]=j;  while (j-q[l]>h[i].c) l++;  dp[i][j]=dp[i-1][q[l]]+s[j]-s[q[l]];   }cout<<dp[m][n];}