牛客初试 日期:2020.10.17 普及组 目标苟分 260pts
T1
牛牛的密码
感觉挺简单的,就是一个字符串的处理。
代码如下:
#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
using namespace std;
string s;
string ss[4];
bool le[4];
int level;
int main()
{
cin>>s;
for(int i=0;i<s.size();i++)
{
if(s[i]>='a'&&s[i]<='z')
ss[0]+=s[i],le[0]=1;
else if(s[i]>='A'&&s[i]<='Z')
ss[1]+=s[i],le[1]=1;
else if(s[i]>='0'&&s[i]<='9')
ss[2]+=s[i],le[2]=1;
else
ss[3]+=s[i],le[3]=1;
}
level=le[0]+le[1]+le[2]+le[3];
printf("password level:%d\n",level);
for(int i=0;i<=3;i++)
{
if(le[i]==0)
printf("(Null)");
else
cout<<ss[i];
printf("\n");
}
return 0;
}
T2:牛牛的跳跳棋
这个就比较难了,需要一定的逻辑推理和代码优化才能AC。
首先分析一下,牛牛在第i个位置可以往前或向后跳ai个位置,画个表模拟一下,其实向后跳可以省略。
因为只用求最少要用多少次魔法所以你能往后跳的同时已经说明你可以不用魔法从前面的点跳过来,所以可以省略。
思路:
这道题的数据规模告诉我们只用用O(n)的算法,而且要注意一个细节字典序要最小。
所以考虑当前1~i的最优方案,就是从最远的那个点跳到当前这个点,那么我们可以用一个数组f来存第i点之前最远哪个点可以跳到这个点。
然后再来个数组m表示到了第i个点我用了多少次魔法。
然后总是要记个前驱吧,因为要输出路径。
代码如下
#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
using namespace std;
int n;
int p[100011];
int f[100011];//最远到达哪里
int q[100011];//最小坐标
int h[100011];//前驱
int m[100011],mm;//都是魔法使用次数
int ans[100011];
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;i++)
scanf("%d",&p[i]);
q[0]=1;
for(int i=1;i<=n+1;i++)
{
if(f[i-1]<p[i]+i&&p[i]!=0)
f[i]=p[i]+i,q[i]=i;
else
f[i]=f[i-1],q[i]=q[i-1];
}
for(int i=2;i<=n+1;i++)
{
if(f[i-1]<i)
{
if(f[i-1]+1==i)
q[i]=q[i-1],m[i]=m[q[i]]+1;
else
q[i]=i-1,m[i]=m[i-1]+1;
mm++;
}
}
printf("%d\n",mm);
n++;
do
{
if(m[n]>0)
ans[++ans[0]]=q[n];
n=q[n];
if(n==q[n]&&n!=1)
n--;
}while(n!=1);
for(int i=ans[0];i>=1;i--)
printf("%d ",ans[i]);
return 0;
}
T3 牛牛的最大兴趣组
第三题我后面改了一下,发现自己没有能力拿正解
于是看了一下大佬的代码,良心发现自己思路对了代码错了……
首先对于一个人来讲应该分解成一个质数的平方或立方或者一次方的形式,因为题目要求得是只有加起质数刚好为三的倍数且这个底数要是相同的。
所以想清楚还是挺好解的
代码如下:
#include<map>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define ll long long
#define N 100010
using namespace std;
ll n, x, y, w, xx, ans, a[N], d[N], pp[N];
map<int,int>p;
int main()
{
scanf("%lld", &n);
p[1] = ++w;
for (ll i = 1; i <= n; ++i)
{
scanf("%lld", &x);
xx = x;
y = 1;
for (ll j = 2; j * j <= xx; ++j)
if (xx % j == 0)
{
while (x % (j * j * j) == 0)
xx /= j * j * j, x /= j * j * j;
if (xx % (j * j) == 0) y *= j, xx /= j * j;
else if (xx % j == 0) y *= j * j, xx /= j;
}
if (xx > 1)
y *= xx * xx;
if (p[x]) a[p[x]]++;
else p[x] = ++w, a[w] = 1;
if (!p[y]) p[y] = ++w;
d[p[x]] = p[y];
}
for (ll i = 2; i <= w; ++i)
if (!pp[i])
{
ans += max(a[i], a[d[i]]);
pp[d[i]] = 1;
}
printf("%lld", ans + (a[1]?1:0));
return 0;
}
T4 牛牛的滑动窗口组
这个其实已经太难了,本人无法领悟到AC的境界不过50分还是可以的,主要思想就是dp转移每个以i为起点的最大值和最小值然后每一次转移求出其总和。
代码如下:
#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
using namespace std;
int n;
int num[100001];
int qd[100001][2];
int ans[100001];
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
scanf("%d",&num[i]);
qd[i][0]=num[i];//最大值
qd[i][1]=num[i]; //最小值
}
for(int i=1;i<=n;i++)//长度
for(int j=1;j+i-1<=n;j++)//遍历
{
ans[i]+=qd[j][0]*qd[j][1];
qd[j][0]=max(qd[j][0],num[j+i]);
qd[j][1]=min(qd[j][1],num[j+i]);
}
for(int i=1;i<=n;i++)
printf("%d ",ans[i]);
return 0;
}
请大佬多多指教,因为我是一名蒟蒻,还需在漫长的修行道路上渐行渐远……
576

被折叠的 条评论
为什么被折叠?



