牛客练习赛 16

在各位ak的大佬中,我感觉我寄几好菜啊。。。

题目描述

给定字符串s,s只包含小写字母,请求出字典序最大的子序列。
子序列:https://en.wikipedia.org/wiki/Subsequence
字典序:https://en.wikipedia.org/wiki/Lexicographical_order

输入描述:

一行一个字符串s (1 <= |s| <= 100,000)。

输出描述:

字典序最大的子序列。

示例1

输入

ababba

输出

bbba

示例2

输入

abbcbccacbbcbaaba

输出

cccccbba


A是IQIYI笔试题。。233 。我们让循环一开始的起始位置为$ 0 $。然后做$26$次循环,从‘Z‘到‘A‘。若当前循环的字符为$k$,我们从起始位置开始找所有出现的字符$k$,每出现一次就加到答案字符串末尾,然后更新起始位置为当前位置。这样构造出的一定是字典序最大的字符串。

 1 #include<bits/stdc++.h>
 2 #define clr(x) memset(x,0,sizeof(x))
 3 #define clr_1(x) memset(x,-1,sizeof(x))
 4 #define mod 1000000007
 5 #define LL long long
 6 #define INF 0x3f3f3f3f
 7 using namespace std;
 8 string s,ans;
 9 int pos,p;
10 int main()
11 {
12     ios::sync_with_stdio(false);
13     cin>>s;
14     pos=0;
15     for(char p=‘z‘;p>=‘a‘;p--)
16     {
17         for(int i=pos;s[i];i++)
18         {
19             if(s[i]==p)
20             {
21                 ans+=p;
22                 pos=i;
23             }
24         }
25     }
26     cout<<ans<<endl;
27     return 0;
28 }

题目描述

街上有n棵树,标号为1...n,第i棵树的高度为ai
定义这n棵树是漂亮的,当且仅当
    1. 对于所有的i,ai=an-i+1
    2. 对于1 <= i < n / 2 (不是整除),ai + 1= ai + 1;
比如说 “2 3 4 5 5 4 3 2”和“1 2 3 2 1”是漂亮的而“1 3 3 1”和“1 2 3 1”不是。
现在请问最少修改几棵树的高度(可以变大也可以变小),使得这些树是漂亮的。

输入描述:

第一行一个整数n表示树的数量( 1 <= n <= 100,000)。第二行n个整数表示树的高度( 1 <= a

i

<= 100,000)。

输出描述:

输出一个整数表示最少修改树的高度的数目。

示例1

输入

3
2 2 2

输出

1

示例2

输入

4
1 2 2 1

输出

0


我们先考虑前$ \frac{n+1}{2} $ 的数字,由于$a_i-a_{i-1}=1 $,所以必须调成递增的差值为$1$的递增序列。我们最朴素的想法是先确定$a_1$的值,对于不同的$ a_1=k $我们算有多少个$a_i =k+i $,找最大的那个。这样就把$ a_i $分成了几个集合。但是这样枚举$k$想想会超时。但是这时你会惊奇的发现,对于在一个集合里的元素$ a_i-i  $是相同的。因此我们统计一下对于每个值$a_i-i $的数量。对于后半段的数字也是类似的操作。然后我们找这些数量的最大值$maxn$。$n-maxn$就是答案。鉴于可能出现负数,做桶排的时候下标要在加个$ P=1000000 $。

 1 #include<bits/stdc++.h>
 2 #define clr(x) memset(x,0,sizeof(x))
 3 #define clr_1(x) memset(x,-1,sizeof(x))
 4 #define mod 1000000007
 5 #define LL long long
 6 #define INF 0x3f3f3f3f
 7 using namespace std;
 8 const int N=1e5+10;
 9 const int P=1e5;
10 int n,m;
11 int ans;
12 int a[N];
13 int high[N*2];
14 int main()
15 {
16     scanf("%d",&n);
17     for(int i=1;i<=n;i++)
18         scanf("%d",a+i);
19     m=(n+1)/2;
20     for(int i=1;i<=m;i++)
21     {
22         high[P+a[i]-i]++;
23     }
24     for(int i=m+1;i<=n;i++)
25     {
26         high[P+a[i]-(n-i+1)]++;
27     }
28     ans=0;
29     for(int i=1;i<=2*P;i++)
30         ans=max(ans,high[i]);
31     printf("%d\n",n-ans);
32     return 0;
33 }

题目描述

平面上有若干个点,从每个点出发,你可以往东南西北任意方向走,直到碰到另一个点,然后才可以改变方向。
请问至少需要加多少个点,使得点对之间互相可以到达。

输入描述:

第一行一个整数n表示点数( 1 <= n <= 100)。第二行n行,每行两个整数x

i

, y

i

表示坐标( 1 <= x

i

, y

<= 1000)。y轴正方向为北,x轴正方形为东。

输出描述:

输出一个整数表示最少需要加的点的数目。

示例1

输入

2
2 1
1 2

输出

1

示例2

输入

2
2 1
4 1

输出

0


我们建个图,对于任意两个在同行或同列的点我们都连一条边。如果两点可达,那么这两个点一定在一个联通块里。因此我们拿并查集统计下有多少联通块。若有$k$个联通块,最少加$k-1$个点把这些联通块连起来全部可达了。因此答案为$k-1$。

 1 #include<bits/stdc++.h>
 2 #define clr(x) memset(x,0,sizeof(x))
 3 #define clr_1(x) memset(x,-1,sizeof(x))
 4 #define mod 1000000007
 5 #define LL long long
 6 #define INF 0x3f3f3f3f
 7 using namespace std;
 8 const int N=1e2+10;
 9 int fa[N],ans;
10 int x[N],y[N];
11 int n,m;
12 int Find(int x)
13 {
14     if(fa[x]!=x)
15         fa[x]=Find(fa[x]);
16     return fa[x];
17 }
18 void Union(int u,int v)
19 {
20     fa[Find(u)]=Find(v);
21     return ;
22 }
23 void init(int n)
24 {
25     for(int i=1;i<=n;i++)
26         fa[i]=i;
27 }
28 int main()
29 {
30     scanf("%d",&n);
31     init(n);
32     for(int i=1;i<=n;i++)
33         scanf("%d%d",x+i,y+i);
34     for(int i=1;i<=n;i++)
35         for(int j=1+1;j<=n;j++)
36         {
37             if(x[i]==x[j])
38             {
39                 if(Find(i)!=Find(j))
40                     Union(i,j);
41             }
42             if(y[i]==y[j])
43             {
44                 if(Find(i)!=Find(j))
45                     Union(i,j);
46             }
47         }
48     ans=0;
49     for(int i=1;i<=n;i++)
50         if(fa[i]==i)
51             ans++;
52     ans--;
53     printf("%d\n",ans);
54     return 0;
55 }

题目描述

给定n个数字a1, a2, ..., an
定义f(l, r) = al | al+1| ... | ar
现在枚举(1 <= l <= r <= n),问不同的f值一共有多少个。

输入描述:

第一行一个整数n表示数组大小 (1 <= n <= 100,000);第二行n个整数满足0 <= a

i

 <= 1000,000。

输出描述:

输出一个整数表示不同的f值一共有多少个。

示例1

输入

3
1 2 0

输出

4

示例2

输入

10
1 2 3 4 5 6 1 2 9 10

输出

11


  E的话我们把数按二进制分成$20$位,因此我们现在有两维,一维是序列,一维是数位。我们先要计算一下在当前下标为$i$的位置,每个数位$k$最后一次出现的下标位置,这个可以递推解决。之后后我们做一下前缀或$pre[i]$ (跟前缀和差不多)。

  然后我们接下来固定区间右端点$r$,然后找不同的$l$的情况下会产生的数。这样的数最多$ 20 $个。一开始我们的数是$[1,r]$ 或后的结果,也就是$pre[r]$。我们前面算过下标为$r$,数位$k$出现的最晚位置,那么我们把这些位置和数位按照位置的前后顺序排序,然后把这些数位按前后顺序从$pre[r]$中从$1$变为$0$,这个排序+亦或解决。当然位置相同的必须同时变换。然后每次变换以后看看这个数字是否出现过,没有答案$+1$。因此我们还要写一个标记数组来确认数字是否出现过。

  对了还要特判一下$0$有没有在序列中出现过,有的话答案$ +1 $。

  因此综合一下复杂度差不多$ O(n \ 20 \ log_2 20)$。后面$ 20log_2 20 $是排序的复杂度。

 1 #include<bits/stdc++.h>
 2 #define clr(x) memset(x,0,sizeof(x))
 3 #define clr_1(x) memset(x,-1,sizeof(x))
 4 #define mod 1000000007
 5 #define LL long long
 6 #define INF 0x3f3f3f3f
 7 #define mp(x,y) make_pair(x,y)
 8 using namespace std;
 9 const int N=1e5+10;
10 const int M=5e6+10;
11 int a[N];
12 int pre[N];
13 int head[N][32];
14 struct pa
15 {
16     int pre,bit;
17 }st[32];
18 bool vis[M];
19 int n,m,k,p,tot;
20 int ans;
21 bool cmp(pa a,pa b)
22 {
23     return a.pre<b.pre;
24 }
25 int main()
26 {
27     scanf("%d",&n);
28     ans=0;
29     for(int i=1;i<=n;i++)
30     {
31         scanf("%d",a+i);
32         if(a[i]==0)
33         {
34             vis[0]=1;
35             ans++;
36         }
37         pre[i]=(pre[i-1]|a[i]);
38         p=a[i];
39         for(int k=0;k<32;k++)
40         {
41             if(p&1)
42                 head[i][k]=i;
43             else
44                 head[i][k]=head[i-1][k];
45             p>>=1;
46         }
47     }
48     for(int i=1;i<=n;i++)
49     {
50         for(int k=0;k<32;k++)
51             st[k]=(pa){head[i][k],k};
52         sort(st,st+32,cmp);
53         p=pre[i];
54         for(int j=0;j<32;j++)
55         {
56             if(st[j].pre==0)
57                 continue;
58             if(j==0 || st[j].pre!=st[j-1].pre)
59             {
60                 if(!vis[p])
61                 {
62                     ans++;
63                     vis[p]=1;
64                 }
65             }
66             p^=(1<<st[j].bit);
67         }
68     }
69     printf("%d\n",ans);
70     return 0;
71 }

题目描述

给定n个数,从中选出三个数,使得最大的那个减最小的那个的值小于等于d,问有多少种选法。

输入描述:

第一行两个整数n,d(1 <= n <= 100,000,1 <= d <= 1000,000,000);第二行n个整数满足abs(a

i

) <= 1,000,000,000。数据保证a单调递增。

输出描述:

输出一个整数表示满足条件的选法。

示例1

输入

4 3
1 2 3 4

输出

4

示例2

输入

4 2
-3 -2 -1 0

输出

2

示例3

输入

5 19
1 10 20 30 50

输出

1


这也是一个水题。你先排序一下。当确定最大值为 $ a_j $时, 用lower_bound找找前面大于等于 $ a_j - d $的第一个数$ a_i $,因此我们可以在 $ [ i , j-1 ] $中任选两个数作为一个组合,对答案的贡献为$ C_{j-i}^2 $。

 1 #include<bits/stdc++.h>
 2 #define clr(x) memset(x,0,sizeof(x))
 3 #define clr_1(x) memset(x,-1,sizeof(x))
 4 #define mod 1000000007
 5 #define LL long long
 6 #define INF 0x3f3f3f3f
 7 using namespace std;
 8 const int N=1e5+10;
 9 int n,d,p;
10 int a[N];
11 LL ans;
12 int main()
13 {
14     scanf("%d%d",&n,&d);
15     for(int i=1;i<=n;i++)
16         scanf("%d",a+i);
17     sort(a+1,a+n+1);
18     ans=0;
19     for(int i=3;i<=n;i++)
20     {
21         p=lower_bound(a+1,a+i,a[i]-d)-a;
22         if(p<=i-2)
23             ans+=(LL)(i-p)*(i-p-1)/2;
24     }
25     printf("%lld\n",ans);
26     return 0;
27 }

原文地址:https://www.cnblogs.com/wujiechao/p/8965134.html

时间: 2024-10-08 18:37:48

牛客练习赛 16的相关文章

牛客练习赛16

A   字典序最大的子序列 > 25960019 一开始潜意识看成了循环,最长子串-- 找每个字母最晚出现的位置,那么比它小的字符必须出现在 在它之后的位置 1 #include <cstdio> 2 #include <cstdlib> 3 #include <cstring> 4 #include <cmath> 5 #include <set> 6 #include <map> 7 #include <list>

牛客练习赛16 B求值

题目描述 给定n个数字a1, a2, ..., an.定义f(l, r) = al | al+1| ... | ar.现在枚举(1 <= l <= r <= n),问不同的f值一共有多少个. 输入描述: 第一行一个整数n表示数组大小 (1 <= n <= 100,000):第二行n个整数满足0 <= ai <= 1000,000. 输出描述: 输出一个整数表示不同的f值一共有多少个. 示例1 输入 3 1 2 0 输出 4 示例2 输入 10 1 2 3 4 5

【牛客】牛客练习赛16(未完)

A  字典序最大的子序列 题意:给定字符串s,s只包含小写字母,请求出字典序最大的子序列.(看例子就能看明白) 思路:从这个字符串a后面开始比较,先把最后一个字母存进s,然后那那s中最新的一个元素跟a中上一个进行比较,如果a不比s小,则存入s,并把这个看做新哒~ #include<bits/stdc++.h> using namespace std; typedef long long ll; const int inf = 0x3f3f3f3f; char s[100007]; int ma

牛客练习赛11 B trie树+拓扑判环 E 分治求平面最近点对

牛客练习赛11 B  假的字符串题意:给定n个字符串,互不相等,你可以任意指定字符之间的大小关系(即重定义字典序),求有多少个串可能成为字典序最小的串,并输出它们. tags:好题 对于一个字符串, 1]如有其它字符串是它的前缀,那肯定不可能.这个直接用字典树处理就可以. 2]但如果以这个字符串为最小,怎么判定其它字符串不会矛盾呢? 其实矛盾的情况详细一点说是: 比如要以  abcd 为最小, 但又有另一个字符串 aba ,这就矛盾了. 对这种情况,在跑字典树的时候,我们对有相同父亲结点的多个儿

牛客练习赛18

链接:https://www.nowcoder.com/acm/contest/110/A来源:牛客网 最大乘积 时间限制:C/C++ 1秒,其他语言2秒 空间限制:C/C++ 262144K,其他语言524288K 64bit IO Format: %lld 题目描述 这题要你回答T个询问,给你一个正整数S,若有若干个正整数的和为S,则这若干的数的乘积最大是多少?请输出答案除以2000000000000000003(共有17 个零) 的余数. 举例来说,当 S = 5 时,若干个数的和为 5

转载:牛客练习赛17 c 规律题

转载:https://www.cnblogs.com/zzqc/p/8995135.html C.链接:https://www.nowcoder.com/acm/contest/109/C来源:牛客网 题目描述 给定长度为n的数组a,定义一次操作为:1. 算出长度为n的数组s,使得si= (a[1] + a[2] + ... + a[i]) mod 1,000,000,007:2. 执行a = s:现在问k次操作以后a长什么样. 输入描述: 第一行两个整数n,k(1 <= n <= 2000,

牛客练习赛7 E 珂朵莉的数列(树状数组+爆long long解决方法)

https://www.nowcoder.com/acm/contest/38/E 题意: 思路: 树状数组维护.从大佬那里学习了如何处理爆long long的方法. 1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 using namespace std; 6 typedef long long ll; 7 const int maxn =

牛客练习赛10

A旅游观光 题目描述 有n个地方,编号为1->n,任意两个地方有公交车,从i到j的票价为(i+j)mod(n+1),而且这个票可以用无限次,你要把这些地方全部走一遍,问最小花费为多少.可以在任意地方开始和结束. 输入描述: 第一行一个数n 输出描述: 输出一行一个数表示答案 示例1 输入 10 输出 4 说明 1 -> 10 -> 2 -> 9 -> 3 -> 8 -> 4 -> 7 -> 5 -> 6,代价是4 备注: 对于100%的数据,有1

牛客练习赛1 补题记录

A 矩阵 中文题意,要找一个最大的k阶子矩阵在原矩阵中出现过两次. 需要将这个矩阵进行Hash,也就是需要二维Hash,先把每一行Hash了,再把每一列Hash了,有一点前缀的感觉. 预处理完Hash值之后,二分答案k,check过程是在$O(n ^ 2)$枚举起点,这里其实枚举终点方便一些,边界比较好处理,把每个k阶矩阵的hash值存下来,最后看有没有两个一样的. 1 #include <bits/stdc++.h> 2 using namespace std; 3 4 const int