总体情况
本次题目暴枚较多,弄不好容易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 long
cin>>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];
}