T1 | 牛牛的密码 |
---|---|
T2 | 牛牛的跳跳棋 |
T3 | 牛牛的最大兴趣组 |
T4 | 牛牛的滑动窗口 |
T1
链接:https://ac.nowcoder.com/acm/contest/7604/A
来源:牛客网
牛牛在注册不同的网站时,总是会使用不同的密码来保证他的账号安全。
为了保证他的密码强度,牛牛使用他的“字符串筛选器”来测试密码的强度。
具体来说,他先将输入的字符串筛选分成四部分。
第一部分仅由小写英文字母组成
第二部分仅由大写英文字母组成
第三部分仅由0到9的数字组成
第四部分由其余特殊字符组成
这四部分要保留它们在原字符串中的相对顺序。
比如将"1q2w3E4R5{6}"这个字符串进行筛选后
四部分分别为:“qw”、“ER”、“123456”、"{}"。
然后只要某一部分不为空,牛牛就认为他的密码等级高1级。
密码等级最低为1级,最高4级。
例如"asdA@123"的密码等级为4,"20020101"的密码等级为1。
请帮助牛牛判断他注册账号时的密码等级,以及该密码做字符串筛选后的结果。
暴力
#include<iostream>
#include<cstdio>
using namespace std;
int n, m;
string s;
string s1, s2, s3, s4;
int main()
{
cin>>s;
s1=s2=s3=s4="(Null)";
for(int i=0; i<s.size(); i++)
{
if(s[i]>='0'&&s[i]<='9')
{
if(s3=="(Null)")
s3=s[i];
else s3+=s[i];
}
else if(s[i]>='a'&&s[i]<='z')
{
if(s1=="(Null)")
s1=s[i];
else s1+=s[i];
}
else if(s[i]>='A'&&s[i]<='Z')
{
if(s2=="(Null)")
s2=s[i];
else s2+=s[i];
}
else{
if(s4=="(Null)")
s4=s[i];
else s4+=s[i];
}
}
if(s1!="(Null)")
m++;
if(s2!="(Null)")
m++;
if(s3!="(Null)")
m++;
if(s4!="(Null)")
m++;
printf("password level:%d\n", m);
cout<<s1<<endl<<s2<<endl<<s3<<endl<<s4;
return 0;
}
T2
链接:https://ac.nowcoder.com/acm/contest/7604/B
来源:牛客网
牛牛最近在玩一种叫做跳跳棋的游戏,棋盘可以看成是一个一维的线性数组,编号从1到n+1。
一开始牛牛的棋子位于第1个格子,游戏的最终目的是将棋子移动到第n+1个格子。
棋盘1~n的每个格子都有一个“弹力系数”的权值p_ip
i
。
当棋子位于第i个格子时,它的下一步可以移动到[i-p_i,i+p_i][i−p
i
,i+p
i
]范围内的任意一个格子。
举例来说,假设第3个格子的弹力系数为2,那么牛牛下一步可以移动到第1,2,3,4,5格中的任意一格。
现在给定1~n每格的弹力系数p_ip
i
。
牛牛发现,好像有时由于棋盘的p_ip
i
设置不合理,导致游戏无法通关。
所以牛牛准备施展他神奇的魔法,他每次施展魔法都可以使得一个格子的弹力系数p_ip
i
+1,他可以施展若干次魔法操作不同的格子,但是要求他不能够重复对一个格子施展魔法。
牛牛想要知道,为了使跳跳棋通关,他最少施展多少次魔法,并且他应该操作哪些格子。
请输出牛牛的最小操作次数,以及施展魔法的操作序列,操作序列的第i个数表示该次施展魔法的格子编号,由于答案不唯一,所以请你输出一个最小字典序的答案。
最小字典序指:在保证第1个数字尽可能小的前提下,保证第2个数字尽可能的小,然后在此前提下保证第3个数字尽可能的小…以此类推。
暴力20
#include<iostream>
#include<cstdio>
using namespace std;
int n;
int a[100010], b[100010], c[100010], ans=1000100;
bool check(int k)
{
for(int i=1; i<=k; i++)
if(b[i]<c[i])
return 1;
else if(b[i]>c[i])
return 0;
return 0;
}
void dfs(int x, int k)
{
if(x>n)
{
if(k<ans)
{
for(int i=1; i<=k; i++)
c[i]=b[i];
ans=k;
}
else if(k==ans)
{
if(check(k)){
for(int i=1; i<=k; i++)
c[i]=b[i];
}
}
return;
}
if(a[x]!=0)
{
for(int i=x+1; i<=a[x]+x; i++)
dfs(i, k);
}
b[k+1]=x;
dfs(x+a[x]+1, k+1);
}
int main()
{
scanf("%d", &n);
for(int i=1; i<=n; i++)
scanf("%d", &a[i]);
dfs(1, 0);
printf("%d\n", ans);
for(int i=1; i<ans; i++)
printf("%d ", c[i]);
if(ans!=0)
printf("%d", c[ans]);
return 0;
}
T3
链接:https://ac.nowcoder.com/acm/contest/7604/C
来源:牛客网
牛牛的班级中有n个人,他们的性格各不相同。
牛牛现在想要从这n个人中选出一些人组成一个兴趣小组,但是他想让参加这个兴趣小组的人数尽可能的多。但是他有不想让其中有任何一对人之间由于性格问题产生矛盾。
具体来说,如果这个兴趣小组中出现两个人性格值的乘积开三次方根是一个正整数,就认为他们两个性格不合。
比如一个性格值为2的同学和一个性格值为4的同学就是性格不合的,因为24=8,而一个性格值为2的同学和一个性格值为8的同学性格相合,可以出现在同一个兴趣小组中,因为28=16,16开三次方根不是一个正整数。
T4
链接:https://ac.nowcoder.com/acm/contest/7604/D
来源:牛客网
牛牛最近学习了滑动窗口类的算法,滑动窗口算法可以解决一些线性数组的离线静态区间查询类问题。
具体来说,假设对于一个数组进行m次静态区间查询问题。如果这些查询满足条件:\forall i,j∀i,j当l_i \leq l_jl
i
≤l
j
时,总有r_i \leq r_jr
i
≤r
j
。(i,j表示查询的编号,l,r表示查询的左右端点)
接下来只要查询的问题满足可以快速插入和删除单点,就可以使用滑动窗口优化,将这m次查询的复杂度降低到O(n)。
显然,如果对于一个数组的区间查询问题,查询的区间长度给定为k时,总是满足\forall i,j∀i,j当l_i \leq l_jl
i
≤l
j
时,总有r_i \leq r_jr
i
≤r
j
这一条件的。
牛牛接下来想要问你的问题也和定长滑动窗口有关。
众所周知,长度为k的滑动窗口从左到右去截取一个长度大小为n的数组时,一共可以截取到n-k+1个子数组。
牛牛将这n-k+1个子数组的极大值与极小值的乘积求和称为该数组的"第k窗口值"。
举个例子,假设长度为5的数组为[1,5,2,4,3],长度为3的滑动窗口可以截取三个子数组,它们分别为[1,5,2],[5,2,4],[2,4,3]。
所以该数组的“第3窗口值”为15+25+2*4=23。
对于一个给定大小的数组n,牛牛现在想要知道它的第1,2,3,4,5…n窗口值各是多少,请你编写程序解决他的问题。
单调队列暴力50
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
int n, m, k, head, tail;
int q[100100], a[100100], minn[100100], maxx[100100];
int main(){
scanf("%d", &n);
for(int i=1; i<=n; i++) scanf("%d", &a[i]);
m=1;
while(m<=n)
{
head=1;
tail=0;
memset(q,0,sizeof(q));
for(int i=1; i<=n; i++){
int x=i-m+1;
while(head<=tail&&q[head]<x)head++;
while(tail>=head&&a[i]<a[q[tail]])tail--;
tail++;
q[tail]=i;
if(x>=1)minn[0]++, minn[minn[0]]=a[q[head]];
}
memset(q, 0, sizeof(q));
head=1;
tail=0;
for(int i=1; i<=n; i++)
{
int x=i-m+1;
while(head<=tail&&q[head]<x)head++;
while(tail>=head&&a[i]>a[q[tail]])tail--;
tail++;
q[tail]=i;
if(x>=1)maxx[0]++, maxx[maxx[0]]=a[q[head]];
}
long long ans=0;
for(int i=1; i<=maxx[0]; i++)
ans+=maxx[i]*minn[i];
if(m!=n)
printf("%lld ", ans);
else printf("%lld", ans);
m++;
maxx[0]=minn[0]=0;
}
return 0;
}