acwing周赛39-42(水题实录)

39.第一次打acwing
实话实说,acwing这个平台也还不错,虽然周赛有点水,但是可以增加我的信心加快我的代码速度与熟练度,还有就是对一些板子更加熟悉一点
a.水题
b.

https://www.acwing.com/problem/content/description/4306/

题意:给你q行数据,每行两个字符串,为节点字符串与和这个节点直接相连的字符串,最后输出所有的链表头和尾。
我的思路:用两个map维护每一个链表头和链表尾即可
代码:

#include<bits/stdc++.h>
using namespace std;
unordered_map<string,string>head,tail;

int n;
int main(){
	cin>>n;
	while(n--){
		string a,b;
		cin>>a>>b;
		if(!tail.count(a))head[a]=b,tail[b]=a;
		else head[tail[a]]=b,tail[b]=tail[a],tail.erase(a);
	}
	cout<<head.size()<<endl;
	for(auto& [a,b]:head)cout<<a<<' '<<b<<endl;

return 0;}

c.

https://www.acwing.com/problem/content/description/4307/

题意:给n个字符串,如果字符串s1与s2中有至少一个公共字母,则归为同一类,这类关系具有传递性。问最后字符串能被划分为几类。
我的思路:开了一个并查集+一个map,并查集用来存26个字母的所属关系,map用于筛选掉没有出现过的字母,最后满足fa[i]==i且map中存过的i计入答案中即可
代码:

#include<bits/stdc++.h>
using namespace std;
int fa[26],mp[26]={0};
int find(int x){
	if(fa[x]==x)return x;
	else return find(fa[x]);
}
int main(){int cnt=0;
int m;cin>>m;
for(int i=0;i<26;i++){
fa[i]=i;mp[i]=0;}
for(int i=0;i<m;i++){
	string s;cin>>s;
	for(int j=0;j<s.length();j++){
	   
	 fa[find(s[j]-'a')]=find(s[0]-'a');
	 mp[fa[s[0]-'a']]++;
	}
}
for(int i=0;i<26;i++){
	if(mp[find(i)]&&find(i)==i)cnt++;
	
}
cout<<cnt<<endl;
return 0;}

40
很久后才补的题解,确实是没啥印象了。
a.黑曜石-岩浆
b.

https://www.acwing.com/problem/content/4309/

大意是给一个整数序列,每次对一个数进行加减1的操作,问最少多少次操作能使序列中个数互不相同。
这个题我开map被卡了,一直换思路,最后ac后发现只要开一个unordered_map就能过
我的思路:先把序列中的数及其出现次数用map记录下来,然后升序排序,遍历序列,如果i重复出现了k次(k个i)那么从i+1,i+2,..i+k每个位置放一个,总共需要1+2+...+n次操作
代码:

#include<bits/stdc++.h>
using namespace std;
map<int,int>mp;
int a[6010];
int main(){
int n;cin>>n;
for(int i=0;i<n;i++){cin>>a[i];
if(!mp.count(a[i]))mp[a[i]]=1;
else mp[a[i]]++;}
sort(a,a+n);
int cnt=0;
/*for(int i=1;i<n;i++){
	if(mp[a[i]]>1){
	
	for(int j=1;j<=mp[a[i]]-1;j++){
		mp[j]++;cnt+=j;
	}mp[a[i]]=1;
	}
	
}*/
for(int i=1;i<=n*2;i++){
	if(!mp.count(i)||mp[i]==1)continue;
	else{
		for(int j=1;j<=mp[i]-1;j++){
			if(mp.count(i+j))mp[i+j]++;
			else mp[i+j]=1;cnt+=j;
		}mp[i]=1;
	}
}
cout<<cnt<<endl;
return 0;}

然后有个更暴力的做法,就是如果i重复k次,就直接让i+1加上k-1

a题竟然WA了两发,着实是有点心急而导致翻车
b.

https://www.acwing.com/problem/content/submission/code_detail/11570173/

大意是给你一个二维平面上的n个点,给一个基准点,问你总共有多少条过基准点和n个点中一点的直线。时间有些久远,我已经忘却我怎么WA的了 QAQ
其实这题挺水的,用pair<int,int>存一下x,y坐标,把斜率用map存起来即可

#include<bits/stdc++.h>
#define ll long long 
using namespace std;
pair<int,int>a[1010],b[1010];
map<double,int>mp;
double c[1010];
int main(){
int n,x,y;int cnt=0;
cin>>n>>x>>y;
for(int i=1;i<=n;i++)cin>>a[i].first>>a[i].second;
for(int i=1;i<=n;i++){
	
	b[i].first=a[i].first-x;
	b[i].second=a[i].second-y;
	if(b[i].first){
	c[i]=double(b[i].second)/double(b[i].first);
	if(!mp[c[i]])mp[c[i]]=1;
	else cnt++;}
	else {
	if(!mp[100000])mp[100000]=1;
	else cnt++;
	}
	
}
cout<<n-cnt<<endl;
return 0;}

42
这次状态不怎么样,有点卡题~
老规矩,a题水题
b.

https://www.acwing.com/problem/content/4315/

大意是给你两个字符串,q次询问s1的[l,r]中有几个s2
数据范围:(wssb,写博客的时候才发现我把n,m范围看错了,我说我怎么一直segmation fault,气抖冷)
s1,s2,长度 1<=n,m<=1000,1<=q<=\(10^{5}\)(啊啊啊我看成30%的数据范围了)

我的思路:q较大,因此尽量离线操作,在询问前先处理出结果
处理形式为n*n数组,记录从各个左端点到右端点的ans
建立一个ok数组,初始化为1,遍历s1,如果s1[i]==s2[0],遍历s2比对,匹配失败则ok[i]=0;

#include<bits/stdc++.h>
#define ll long long
using namespace std;

int main(){int ok[50],cnt[50][50]={0};
for(int i=0;i<50;i++)ok[i]=1;
	int n,m,q;
	cin>>n>>m>>q;
	string s1,s2;
	cin>>s1>>s2;
	for(int i=0;i<n;i++){
		if(i+m>n){
			ok[i]=0;continue;
		}
		else if(s1[i]==s2[0]){
			for(int j=i;j<i+m;j++){
				if(s1[j]!=s2[j-i]){
					ok[i]=0;break;}
		}}
		else {ok[i]=0;continue;
	}}
	for(int i=0;i<n-1;i++){
		for(int j=i+1;j<n;j++){
			for(int k=i;k<=j;k++){
				if(ok[k]&&k+m-1<=j)cnt[i][j]++;
			}
		}
	}
	
	for(int i=1;i<=q;i++){
		int l,r;cin>>l>>r;
		if(n<m||l>=r)cout<<"0"<<endl;
		else cout<<cnt[l-1][r-1]<<endl;
		//cout<<a[0]<<endl;
	//	for(int i=0;i<n;i++)cout<<ok[i]<<' ';
	}
return 0;}

结果yxc直接搞了一个stl出来秒杀了这个题,我的内心是崩溃的,化身愤怒的罚时巨兽~~
y总代码:


#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 1010;
int n, m, Q;
string S, T;
char strs[N], strt[N];
int s[N];
int main()
{
    scanf("%d%d%d", &n, &m, &Q);
    scanf("%s%s", strs, strt);
    S = strs, T = strt;
    S = ' ' + S;
for (int i = m; i <= n; i ++ )
    {
        s[i] = s[i -1 ];
        if (S.substr(i - m + 1, m) == T)
            s[i] ++ ;
    }
while (Q -- )
    {
        int l, r;
        scanf("%d%d", &l, &r);
        l += m - 1;
        if (l > r) puts("0");
        else printf("%d\n", s[r] - s[l - 1]);
    }return 0;
}

知道了string.substr()这个函数之后这题也很水了,主要再学习一些y总的思路:
处理从1到i的ok[i],用前缀和给出ans,时间复杂度为o(n)

posted @ 2022-03-13 11:23  misasteria  阅读(51)  评论(0编辑  收藏  举报