A:
链接:https://ac.nowcoder.com/acm/contest/372/A
来源:牛客网
某天,一只可爱的肥橘喵在路上走,突然遇到了一个怪人,那怪人自称PM6,“小肥喵,这里有一道水题,答对了我就请你吃狗肉,答错了你就请我吃猫肉!”
喵咪瑟瑟发抖:“QAQ什么题?”
PM6道:“给你坐标轴上的N个点,求出对于每个点,有多少个点的 X 坐标和 Y 坐标都大于它。”
毫不意外,蠢肥喵完全不会这道题并面临着被做成猫肉火锅的危险,求求你救救喵咪!
输入描述:
输入包括两行,第一行是正整数n,表示点数,接下来N行每行两个数表示第i个点的横坐标和纵坐标,坐标值都是整数,输入数据中存在坐标相同的点。
对于50%的数据:0<=点的坐标大小<=10000,0<=N<=100
对于100%的数据:0<=点的坐标大小<=10000,0<=N<=1000
输出描述:
输出包括N行,第i行表示有多少个点在点i的右上方。
示例1
输入
复制
3
1 2
2 3
4 4
输出
复制
2
1
0
解题报告:
暴力没啥好说的。
AC代码:
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<queue>
#include<map>
#include<vector>
#include<set>
#include<string>
#include<cmath>
#include<cstring>
#define ll long long
#define pb push_back
#define pm make_pair
using namespace std;
const int MAX = 2e5 + 5;
pair<int,int> p[MAX];
int main()
{
int n;
cin>>n;
for(int i = 1; i<=n; i++) {
scanf("%d%d",&p[i].first,&p[i].second);
}
for(int i = 1; i<=n; i++) {
int ans = 0;
for(int j = 1; j<=n; j++) {
if(p[j].first > p[i].first && p[j].second > p[i].second) ans++;
}
printf("%d\n",ans);
}
return 0 ;
B:
题干:
链接:https://ac.nowcoder.com/acm/contest/372/B
来源:牛客网
某天,一只可爱的小兔砸在路上蹦蹦跳跳地走着,怪人PM6出现了,于是小兔子被盯上了。
PM6:“免子。哦不,小兔子。你长得真好…不对,真可爱。我这里有一道很容易很容易的题目,答对了我就请你吃萝卜,答错了你就请我吃兔肉,好不好呀~~?”
小兔砸:“萝卜!?好呀好呀好呀。”于是笨笨的兔纸入套了。
PM6:“我这里有一个由 N 个数组成的序列,给你 M 个询问,每个询问会给你一个数 X ,对于每个询问,你要回答出序列中与这个值最接近的元素。”
听完题后,兔子吓成一坨免子了,面临着变成红烧兔头的危险,求求你救救兔子!
输入描述:
第一行包含一个整数N,为序列长度。
第二行包含N个整数,为序列各元素。
第三行包含一个整数M,为PM6的询问个数。
接下来M行,每行一个整数X,为要询问最接近元素的给定值。
对于40%的数据:1<=N<=10000,1<=M<=1000
对于另外10%的数据:M=1
对于100%的数据:1 <=N<= 100000,1<=M<=10000,0<=序列中的每个数,X<=1e9
输出描述:
M行,每行有一个整数,为最接近相应给定值的元素值,保持输入顺序。若有多个值满足条件,输出最小的一个。
示例1
输入
复制
5
2 4 5 5 7
3
2
5
6
输出
复制
2
5
5
解题报告:
二分就好了,注意特判第一个数和最后一个数,因为这两个不能用下面那个通式(因为可能pos-1==0 或者pos==n+1,此时不能放到数组中取对应数(因为都是0))(貌似很多人因为没有特判所以80分了这题。。)
AC代码:
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<queue>
#include<map>
#include<vector>
#include<set>
#include<string>
#include<cmath>
#include<cstring>
#define ll long long
#define pb push_back
#define pm make_pair
using namespace std;
const int MAX = 2e5 + 5;
int a[MAX];
int main()
{
int n,m;
cin>>n;
for(int i = 1; i<=n; i++) scanf("%d",a+i);
sort(a+1,a+n+1);
cin>>m;
while(m--) {
int x;
scanf("%d",&x);
int pos = lower_bound(a+1,a+n+1,x) - a;
if(pos == 1) {
printf("%d\n",a[1]);continue;
}
if(pos == n+1) {
printf("%d\n",a[n]);continue;
}
if(abs(a[pos] - x) >= abs(a[pos-1]-x)) printf("%d\n",a[pos-1]);
else printf("%d\n",a[pos]);
}
return 0 ;
}
C:
题干:
链接:https://ac.nowcoder.com/acm/contest/372/C
来源:牛客网
另一天,一只可爱的围着围巾的肥企鹅在路上摇摇晃晃地走着,遇上了迎面走来的打着饱嗝的PM6。小企鹅预感不妙,这不就是最近有名的恶人PM6么!吓得立刻扭头就想跑。
PM6:“小火汁,站住!我不吃你(谁叫你是保护动物)。我这有一道简单题,如果你答对了,我就给你吃鱼肉,如果你答错了,就免费帮我充游戏币!”
企鹅:“_(:3J∠)_(默默摘掉围巾)”
PM6:“我给你一个文本串 S ,再给你两个串A、B,你要将文本串中的 A 都转换成 B ,转换后的字符不再参与转换,输出最终的文本串。”
求求你救救企鹅!
输入描述:
第一行输入一个文本串 S 。
第二行输入字符串 A 。
第三行输入字符串 B 。
|S|为S的长度,|A|为A的长度,|B|为B的长度,所有字符都是小写字母,保证 |A| <= |S| 。
对于50%的数据:1<= |A|、|B|、|S| <=1000
对于100%的数据:1<= |A|、|B|、|S| <=1000000
输出描述:
只有一行,输出转换后的文本串。
示例1
输入
复制
abababcd
ab
cd
输出
复制
cdcdcdcd
解题报告:
KMP就好了,记录下来每一个匹配的第一个位置,然后遍历整个字符串,遇到匹配的位置的时候就输出替换串,直到遍历完第一个字符串。
AC代码:
#include<cstdio>
#include<cstring>
#define ll long long
using namespace std;
char s[1000005];
char t[1000005];
char ac[1000005];
int Next[1000005];
int ans[1000005];
int len1,len2,cnt;
void getnext() {
int j = 0,k = -1;
Next[0] = -1;
while(j<len2-1) {
if(k == -1 || t[j] == t[k]) {
j++,k++;
Next[j] = k;
} else k = Next[k];
}
}
int kmp() {
int i=0,j=0;
while(i < len1) {
if(j == -1 || s[i] == t[j]) {
i++,j++;
} else {
j=Next[j];
}
if(j >= len2) {
ans[++cnt] = i-len2;
j=0;
}
}
return cnt;
}
int main() {
scanf("%s",s);
scanf("%s",t);
scanf("%s",ac);
len1 = strlen(s);
len2 = strlen(t);
getnext();
kmp();
//printf("%d\n",kmp());
int cur = 1;
int i = 0;
//cout << "ans**" << ans[1]<<endl;
while(1) {
if(i >= len1) break;
if(cur <= cnt) {
while(i < ans[cur]) {
printf("%c",s[i]);i++;
}
cur++;
i += len2;
printf("%s",ac);
}
else {
printf("%c",s[i]),i++;
}
}
return 0;
}
题干:
链接:https://ac.nowcoder.com/acm/contest/372/D
来源:牛客网
可能很多人要吐槽为什么标题不是“救救blabla”了。
怪人PM6喜欢数糖纸,不同的糖纸有不同的颜色,一共有 N 张糖纸,第 i 张糖纸颜色为 Ci ,它们的位置都是固定的。PM6喜欢五彩缤纷的糖纸,所以他不希望有重复的颜色。他有一次机会,可以收集任意一段连续区间内的糖纸。求出PM6最多能收集多少张糖纸。
输入描述:
第一行一个正整数 N ,表示共有 N 张糖纸。
第二行共有 N 个正整数,第 i 个正整数表示第 i 张糖纸的颜色 Ci
对于20%的数据:1<=N<=100
对于40%的数据:1<=N<=1000
对于100%的数据:1<=N<=1e6,0<=Ci<=1e9
输出描述:
一个整数表示PM6最多能收集多少张糖纸。
示例1
输入
复制
5
1 2 2 3 4
输出
复制
3
说明
PM6可以收集第3到第5张的糖纸,共有三张。
解题报告:
尺取法。
AC代码:(每次固定右边界,来移动左边界)
#include<stdio.h>
#include<iostream>
#include<algorithm>
#include<string.h>
using namespace std;
#define maxn 1000000
int a[maxn+5];
bool b[1000000005];
int main()
{
int n;
scanf("%d",&n);
for(int i=1;i<=n;i++)
scanf("%d",&a[i]);
int l=0,ans=1;
for(int i=1;i<=n;i++){
while(b[a[i]])
b[a[++l]]=false;
b[a[i]]=true;
ans=max(ans,i-l);
}
printf("%d\n",ans);
return 0;
}
AC代码2:(固定左边界看可以到达的右边界)
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<queue>
#include<map>
#include<vector>
#include<set>
#include<string>
#include<cmath>
#include<cstring>
#define ll long long
#define pb push_back
#define pm make_pair
using namespace std;
const int MAX = 2e6 + 5;
const int FFF = 5e7 + 6;
int mp[MAX];
int cnt,a[MAX];
bool vis[FFF];
int HH(int x) {
return (1LL*13531*x)%(FFF-100);
}
int main()
{
int n;
cin>>n;
for(int i = 1; i<=n; i++) scanf("%d",&a[i]),mp[i] = HH(a[i]);
int l = 1,r = 1,ans = 0;
while(l<=r && l <= n) {
while(vis[mp[r]] == 0 && r <= n) {
vis[mp[r]] = 1,r++;
}
ans = max(ans,r-l);
vis[mp[l]] = 0;
l++;
}
printf("%d\n",ans);
return 0 ;
}
这个实现方法很多,可以Hash可以直接开1e9的数组可以unordered_map,可以用二分来离散化(但是离散化完了要重新记录到一个数组中,这样使用的时候是O1的,不能每次使用都从重新计算,因为常数有点扛不住、、)
并且Hash的时候注意不能用rand(),不然可能本来相同的值可能就会被映射到不同地方去了。
这样写显然错误:(越界了)
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<queue>
#include<map>
#include<vector>
#include<set>
#include<string>
#include<cmath>
#include<cstring>
#define ll long long
#define pb push_back
#define pm make_pair
using namespace std;
const int MAX = 2e6 + 5;
const int FFF = 5e7 + 6;
int mp[MAX];
int cnt,a[MAX];
bool vis[FFF];
int HH(int x) {
return (1LL*13531*x)%(FFF-1);
}
int main()
{
int n;
cin>>n;
for(int i = 1; i<=n; i++) scanf("%d",&a[i]),mp[a[i]] = HH(a[i]);
int l = 1,r = 1,ans = 0;
while(l<=r && l <= n) {
while(vis[mp[a[r]]] == 0 && r <= n) {
vis[mp[a[r]]] = 1,r++;
}
ans = max(ans,r-l);
vis[mp[a[l]]] = 0;
l++;
}
printf("%d\n",ans);
return 0 ;
}
常数很小的unordered_map(400ms)(我写的就800ms、、)
#include<cstdio>
#include<unordered_map>
using namespace std;
int main()
{
unordered_map<int,int>pos;
int n,x,now=0,ans=1;
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
scanf("%d",&x);
now=i-pos[x]>now?now+1:i-pos[x];
ans=ans>now?ans:now;
pos[x]=i;
}
printf("%d\n",ans);
return 0;
}
还可以直接取模:
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<queue>
#include<map>
#include<vector>
#include<set>
#include<string>
#include<cmath>
#include<cstring>
#define ll long long
#define pb push_back
#define pm make_pair
using namespace std;
#define N 1000001
#define P 1651469
int n,a[N],ans=0;
bool v[N*2];
int main() {
cin>>n;
for(int i=1;i<=n;i++) scanf("%d",&a[i]);
int l=1,r=1;
v[a[1]%P]=1;
while(r<n) {
if(v[a[r+1]%P]) {
while(a[r+1]!=a[l])v[a[l++]%P]=0;
l++;
}
v[a[++r]%P]=1;
ans=max(ans,r-l+1);
}
cout<<ans<<endl;
}
写在后面:
纪念第一场ak...虽然题目很水但毕竟是不熟悉的OI赛制。继续加油!