CF刷题笔记

目录

第1题Mathematical Circus(800)

第2题Fighting Tournament(1400)

第3题Burenka Plays with Fractions(900)

第4题Best Permutation(800)

第5题Digital Logarithm(1400)

第6题Friends and the Restaurant(1200)

 第7题Jumping on Tiles(1100)

 第8题Not a Cheap String(1000)

 第9题Min-Max Array Transformation(1400)

第10题Double Strings(1100)

第11题Mainak and Array(900)

 第12题Parity Shuffle Sorting(1300)

第13题Meeting on the Line (1600)

第14题Reset K Edges(1900)

第15题Phase Shift(1400)

第16题​​​​​​Good Subarrays (Easy Version)(1300)

第17题​​​​​​Coprime(1100)

第18题​​​​​​Smaller(1500)


第1题Mathematical Circus(800)

标签:建设型算法、数学

#include<bits/stdc++.h>
using namespace std;
 
int main()
{
	int T;
	cin>>T;
	while(T--){
		int  n, k;
		cin>>n>>k;
		
		//根据k%4分成4种情况 
		//设x为(a+k) 
		//(a+k)或者b中的任意一个%4=0,则一定可以配对
		//若 (a+k)和b两个都是%4=2(两个都不是4的倍数的整数),则一定可以配对
		 
		//因此要满足配对有两种情况:(1)4的倍数带一个奇数(2)两个都是%4=2
		//因此奇数a必须要(1)+k后变成%4=2  或者(2)+k后变成%4=0   或者(3)+k后仍然是奇数,但能b%4=0 
		
//		if(k%4 == 0) puts("NO");  //必然存在无法配对的奇数 
//		else if(k%4 == 1 || k%4 == 3)  //奇数加上k后变成偶数,两个偶数能满足配对 
//		{
//			puts("YES");
//			for(int i=0; i+4<=n; i+=4)
//			{
//				printf("%d %d\n", i+1, i+2);  //两个偶数 
//				printf("%d %d\n", i+3, i+4);  //4带奇数 
//			}
//			if(n%4 == 2)  //n是偶数,但不一定是4的倍数,此时就多出来两个
//				printf("%d %d\n", n-1, n);  //两个偶数 
//				
//		}
//		else if(k%4 == 2)  //将%4=2的偶数变成%4=0,这样就能带奇数 
//		{
//			puts("YES");
//			for(int i=0; i+4<=n; i+=4)
//			{
//				printf("%d %d\n", i+2, i+1);  //4带奇数 
//				printf("%d %d\n", i+3, i+4);  //4带奇数 
//			}
//			if(n%4 == 2) 
//				printf("%d %d\n", n, n-1);  //4带奇数 
//		}
		
		//第二遍 
		if(k%4==0) puts("NO");
		else if(k%4==1){
			puts("YES");
			for(int i=0; i+4<=n; i+=4)
			{
				printf("%d %d\n", i+3, i+1);  
				printf("%d %d\n", i+2, i+4);
			}
			if(n%4==2) printf("%d %d\n", n-1, n);
		}
		else if(k%4==2){
			puts("YES");
			for(int i=0; i+4<=n; i+=4)
			{
				printf("%d %d\n", i+2, i+3);  
				printf("%d %d\n", i+1, i+4);
			}
			if(n%4==2) printf("%d %d\n", n, n-1);
		}
		else if(k%4==3){
			puts("YES");
			for(int i=0; i+4<=n; i+=4)
			{
				printf("%d %d\n", i+1, i+3);  
				printf("%d %d\n", i+2, i+4);
			}
			if(n%4==2) printf("%d %d\n", n-1, n);
		}
	} 
	return 0;
} 

第2题Fighting Tournament(1400)

标签:二分、数据结构、执行、双指针

#include<bits/stdc++.h>
using namespace std;
 
const int N = 100010;
int main()
{
	int T;
	cin>>T;
	while(T--){
		//第一遍 
//		int a[N], first[N], cnt[N], whowin[N];
//		memset(a, 0, sizeof a);  //实力(强度值),下标是位置 
//		memset(first, 0, sizeof first);  //第一次赢的轮数,下标是实力 
//		memset(cnt, 0, sizeof cnt);  //赢了多少次,下标是实力 
//		memset(whowin, 0, sizeof whowin);  //这一轮赢了的实力是多少,下标是轮数 
//		int n, q;
//		cin>>n>>q;
//		for(int i=1; i<=n; i++) scanf("%d", &a[i]);
//		
//		//预处理 
//		int now = a[1];  //现在赢了的实力是多少 
//		for(int i=2; i<=n; i++)
//		{
//			if(a[i] > now) now = a[i];
//			if(first[now] == 0) first[now] = i-1;  //记录的是轮数,要-1 
//			cnt[now]++;
//			whowin[i-1] = now;  //下标是轮数,要-1 
//		}
//		
//		//询问(时间复杂度为O(1) 
//		while(q--)
//		{
//			int x, k;
//			scanf("%d%d", &x, &k);
//			
//			int ans = 0;
//			x = a[x];  
//			if(k <= n-1)  
//			{
//				if(whowin[k] < x) ans = 0; 
//				else if(whowin[k] == x) ans = k-first[x]+1;
//				else ans = cnt[x];
//			}
//			else ans = cnt[x] + ((x==n) ? (k-n+1) : 0);  //太妙了!! 
//			cout<<ans<<endl;
//		}		
 
		//第二遍 
		int a[N], cnt[N], first[N], who[N];  //赢的次数,第一次赢的轮数、这一轮谁赢了 
		memset(a, 0, sizeof a);
		memset(cnt, 0, sizeof cnt);
		memset(first, 0, sizeof first);
		memset(who, 0, sizeof who);
		
		int  n, q;
		cin>>n>>q;
		for(int i=0; i<n; i++) cin>>a[i];
		pair<int, int> maxs = {a[0], 0};  //力量、位置 
		for(int i=1; i<n; i++)
		{
			if(a[i] > maxs.first) maxs = {a[i], i};
			who[i] = maxs.second;  //从1开始 
			cnt[maxs.second]++;
			if(!first[maxs.second]) first[maxs.second] = i;
		}
		while(q--)
		{
			int t, k;
			cin>>t>>k;
			int ans = 0;
			if(k <= n-1) //n个选手只有n-1轮,比赛轮数是从1开始 
			{
				if(a[t-1] > a[who[k]]) ans = 0;
				else if(a[t-1] == a[who[k]]) ans = k-first[t-1]+1;
				else ans = cnt[t-1];
			}
			else 
			{
				ans = cnt[t-1];
				if(t-1 == maxs.second) ans += k-(n-1);
			}
			cout<<ans<<endl;
		}
	} 
	return 0;
} 

第3题Burenka Plays with Fractions(900)

标签:数学、数论

//A
 
//操作两次,就可以将两个分数的分子变成0,因此最多操作2步,使x==y 
//1。操作0次:x==y 
//2。(1)操作1次:(ax)/b==c/d,那么就只需要a乘上x,x必须是整数,因此当x=(bc)/(ad)为整数时,操作1次
//   (2)a/b==(cx)/d同理, x=(ad)/(bc)是整数时,操作1次 
//   (3)也就是说:bc和ad能能被另一个整除的话,就操作1次 
//	 (4)0对任何数取模都是0(任何数对0取模会直接报错不输出,容易出bug),因此要特判是0的情况 
//3。剩下的情况就是操作两次了 
#include<bits/stdc++.h>
#define LL long long 
using namespace std;
 
//typedef long long LL;
 
int main()
{
	int T;
	cin>>T;
	while(T--)
	{
		int a, b, c, d;  
		cin>>a>>b>>c>>d;
		LL x = (LL)a*d, y = (LL)b*c;  //要开LL,不然两个1e9相乘会爆int,计算过程中也要开LL,不然两个int相乘后他会自动变回int,若相乘结果爆int,变回int时就会出错 
	
		if(x == y) cout<<0<<endl;
		else if(a==0 || c==0 || x%y==0 || y%x==0) cout<<1<<endl;
		else cout<<2<<endl;
	} 
	return 0;
}

第4题Best Permutation(800)

标签:建设性算法、贪心

//
#include <bits/stdc++.h>
#define first fi
#define second se
using namespace std;
 
typedef long long LL;
typedef pair<int, int> PII;
const int N = 110;
int n;
int a[N];
bool st[N];
 
int dfs(int u)
{
	if(u == n-2+1)
	{
		int x = 0;
		for(int i=1; i<=n; i++)
		{
			if(x < a[i]) x += a[i];
			else x = 0;
		}
		if(x == 2*n-1) return 1; 	
		return 0;
	}
	for(int i=1; i<=n; i++)
	{
		if(st[i]) continue;
		a[u] = i;
		st[i] = true;
		
		if(dfs(u+1)) return 1;
		
		st[i] = false;
	}
	return 0;
}
int main()
{
	int T;
	cin>>T;
	while(T--)
	{
		cin>>n;
		memset(st, 0, sizeof st);
		a[n-1] = n-1, a[n] = n;  //这个就是解题关键点 
		st[n-1] = st[n] = true;
		
		dfs(1);
		for(int i=1; i<=n; i++) cout<<a[i]<<" ";
		cout<<endl; 
	}
	return 0;
 } 

第5题Digital Logarithm(1400)

标签:数据结构、贪心、排序

//如果最大的数成对,就消掉,否则f()
//不断在最大元素上重复f()操作即可 
#include <bits/stdc++.h>
#define first fi
#define second se
using namespace std;
 
typedef long long LL;
typedef pair<int, int> PII;
 
int main()
{
	int T;
	cin>>T;
	while(T--)
	{
		int n;
		cin>>n;
		multiset<int, greater<int>> a, b;  //从大到小排序 
 
		for(int i=0; i<n; i++)
		{
			int x;
			scanf("%d", &x);
			a.insert(x);
		 } 
		for(int i=0; i<n; i++)
		{
			int x;
			scanf("%d", &x);
			b.insert(x);
		 } 
		
		int res = 0;
		while(a.size())
		{
			if(*a.begin() == *b.begin())  //a.begin()好像是指针,必须要加* 
			{
				a.erase(a.begin());  
				b.erase(b.begin());
				continue;
			}
			if(*a.begin() > *b.begin()) 
				swap(a, b);  
			int x = *b.begin();
			b.erase(b.begin());  //erase()的参数是指针,所以这里只能写b.begin(),不能写x 
			b.insert(to_string(x).length());
			res++;
		}
		cout<<res<<endl;
	}
	return 0;
 } 

第6题Friends and the Restaurant(1200)

标签:贪心、双指针

//本题核心就是不一定一个正值要带两个负值的,我就只带一个,另一个遗弃掉 
 
//lower_bound( begin,end,num):从数组的begin位置到end-1位置二分查找第一个大于或等于num的数字,
//找到返回该数字的地址,不存在则返回end。通过返回的地址减去起始地址begin,得到找到数字在数组中的下标。
//upper_bound( begin,end,num):查找第一个大于num的数字
//lower_bound( begin,end,num,greater<type>() ):查找第一个小于或等于num的数字
//upper_bound( begin,end,num,greater<type>() ):查找第一个小于num的数字
#include<bits/stdc++.h>
using namespace std;
 
int main()
{
	int T;
	cin>>T;
	while(T--){
		int n;
		cin>>n;
		vector<int> x(n);  //x(n);
		for(int i=0; i<n; i++) cin>>x[i];
		for(int i=0; i<n; i++){
			int y;
			cin>>y;
			x[i] = y-x[i];
		}
		
		sort(x.begin(), x.end());
		
		//第一种方式 
		int ans = 0;
		int p = lower_bound(x.begin(), x.end(), 0)-x.begin();  //二分查找第一个大于或等于0的数字
		for(int i=0, j=n-1; i<p; i++)
		{
			if(j>=p && x[j]+x[i]>=0)
			{
				ans++;
				j--;
			}
		}
		ans += (n-ans-p)/2;  //==((n-1)-ans-p+1)/2;
		cout<<ans<<endl;
 
		//第二种方式
//		int ans = 0;
//		for(int i=0, j=n-1; i<j; j--)
//		{
//			while(i<j && x[i]+x[j]<0) i++;
//			if(i<j && x[i]+x[j]>=0)
//			{
//				ans++;
//				i++;
//			}
//		}
//		cout<<ans<<endl;
		
	} 
	return 0;
} 

 第7题Jumping on Tiles(1100)

标签:建设性算法、字符串

//
#include <bits/stdc++.h>
#define first fi
#define second se
using namespace std;
 
typedef long long LL;
typedef pair<int, int> PII;
const int N=200010;
 
 
int main()
{
	int T;
	cin>>T;
	while(T--)
	{
		string s;
		cin>>s;
		vector<int>q[26];
		int n = s.length();
		for(int i=0; i<n; i++) q[s[i]-'a'].push_back(i+1);
		
		int x = s[0]-'a', y = s[n-1]-'a';
		vector<int> ans;
		if(x < y)
			for(int i=x; i<=y; i++)
				ans.insert(ans.end(), q[i].begin(), q[i].end());
		else if(x > y)
			for(int i=x; i>=y; i--)
				ans.insert(ans.end(), q[i].begin(), q[i].end());
		else if(x == y)
			ans.insert(ans.end(), q[x].begin(), q[x].end());
		printf("%d %d\n", abs(x-y), ans.size());
		for(int i=0; i<int(ans.size()); i++)  //ans.size()返回不是int 
			printf("%d ", ans[i]);
		cout<<endl;
		
		
		
		
	}
	return 0;
 } 

 第8题Not a Cheap String(1000)

标签:贪心

(和第7题类似)

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

typedef pair<int, int> PII;

int main()
{
	cin.tie(0);  //优化 
	int T;
	cin>>T;
	while(T--)
	{
		//tourist的方法,和jiangly好像 
//		string w;
//		int p;
//		cin>>w>>p;
//		
//		int n = w.size();
//		vector<vector<int>> a(26);
//		int sum = 0;
//		for(int i=0; i<n; i++) 
//		{
//			a[w[i]-'a'].push_back(i);
//			sum += w[i]-'a'+1;
//		}
//		vector<bool> st(n, false);  //记住这个语法 
//		for(int i=25; i>=0; i--)
//		{
//			while(sum>p && !a[i].empty())
//			{
//				sum -= i+1;
//				st[a[i].back()] = true;
//				a[i].pop_back();
//			}
//		}
//		
//		for(int i=0; i<n; i++)
//			if(!st[i])
//				cout<<w[i];
//		cout<<endl;	
		
		//自己的方法 
		string w;
		int p;
		cin>>w>>p;
		
		int n = w.length();
		vector<bool> st(n, false);
		vector<PII> q(n);
		for(int i=0; i<n; i++) q[i] = {w[i]-'a'+1, i};
		sort(q.begin(), q.end(), greater<PII>());
		int sum = 0;
		for(int i=0; i<n; i++) sum += q[i].first;
		for(int i=0; i<n; i++)
		{
			if(sum <= p) break;
			sum -= q[i].first;
			st[q[i].second] = true;  //不明白为什么说这里可能越界 
		}
		
		for(int i=0; i<n; i++)
			if(!st[i])
				cout<<w[i];
		cout<<endl;

	}
	return 0;
}

 第9题Min-Max Array Transformation(1400)

标签:二分、贪心、双指针

#include<bits/stdc++.h>
using namespace std;
 
const int N = 100010;
 
int main()
{
	int T;
	cin>>T;
	while(T--)
	{
		int n;
		cin>>n;
		vector<int>a(n), b(n);
		for(int i=0; i<n; i++) cin>>a[i];
		for(int i=0; i<n; i++) cin>>b[i];
		
		for(int i=0; i<n; i++)
		{
			//第一种方法 
			int p = lower_bound(b.begin(), b.end(), a[i])-b.begin();  //第一个大于等于a[i]的
			cout<<b[p]-a[i]<<" ";
			//第二种(双指针)
//			int j = 0;
//			while(b[j]<a[i]) j++;
//			cout<<b[j]-a[i]<<" ";
		}
		puts("");
		for(int i=0, j=0; i<n; i++)
		{
			j = max(j, i);
			while(j+1<n && b[j]>=a[j+1]) j++;
			cout<<b[j]-a[i]<<" ";
		}
		puts("");
		
	}
	return 0;
}

第10题Double Strings(1100)

标签:暴力、数据结构、字符串

TLE代码///
//#include<bits/stdc++.h>
//using namespace std;
//bool check(string &str, vector<string>&s, vector<vector<string>>& map)
//{
//	int len = str.length();
//	for(int i=1; i<len; i++)
//	{
//		for(auto t1:map[i])
//		{ 
//			for(auto t2:map[len-i])
//			{
//				if(str == t1+t2) return true;
//			}
//		}	
//	}
//	return false;
//}
//int main()
//{
//	int T;
//	cin>>T;
//	while(T--)
//	{
//		int n;	
//		cin>>n;
//		vector<string> s(n);
//		vector<vector<string>> map(9);  //从0开始,因此8+1 
//		for(int i=0; i<n; i++)
//		{
//			cin>>s[i];  
//			map[s[i].size()].push_back(s[i]);
//		} 
//		
//		for(int i=0; i<n; i++)
//		{			
//			if(check(s[i], s, map)) cout<<1;
//			else cout<<0;
//		}
//		puts("");
//	}
//	return 0;
//}
//第一种方法(和上面的很像,只不过优化了一下)///
//string sub1 = s.substr(5); //只有一个数字5表示从下标为5开始一直到结尾:sub1 = "56789"
//string sub2 = s.substr(5, 3); //从下标为5开始截取长度为3位:sub2 = "567" 

#include<bits/stdc++.h>
using namespace std;
int main()
{
	int T;
	cin>>T;
	while(T--)
	{
		int n;	
		cin>>n;
//		vector<string> s(n);
		string s[n];  //也可以 
		map<string, bool> mp;  //map的使用和unordered_map类似 
		for(int i=0; i<n; i++)
		{
			cin>>s[i];  
			mp[s[i]] = true;
		} 
		
		for(int i=0; i<n; i++)
		{
			bool ok = false;
			int len = s[i].length();
			for(int j=1; j<len; j++)
			{
				string pre = s[i].substr(0, j);  //注意substr()的用法
				string stuff = s[i].substr(j, len-j);
				if(mp[pre] && mp[stuff]) 
				{
					ok = true;
					break;
				} 
			}
			if(ok) cout<<1;
			else cout<<0;
		}
		puts("");
	}
	return 0;
}

第11题Mainak and Array(900)

标签:贪心、数学

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

int main()
{
	int T;
	cin>>T;
	while(T--)
	{
		int n;
		cin>>n;
		vector<int> a(n);
		for(int i=0; i<n; i++){
			cin>>a[i];
		}
		
		int ans = a[n-1] - a[0];
		for(int i=0; i<n-1; i++){
			ans = max(ans, a[n-1]-a[i]);
		}
		for(int i=0; i<n; i++){
			ans = max(ans, a[i]-a[0]);
		}
		for(int i=0; i<n-1; i++){  //特殊情况 
			ans = max(ans, a[i]-a[i+1]);
		}
		cout<<ans<<endl; 
	}
	return 0;
}

 第12题Parity Shuffle Sorting(1300)

标签:建设性算法、排序

//相同奇偶性的两个数相加为偶数,不同奇偶性相加则为奇数
//原理自己看代码吧 
#include<bits/stdc++.h>
using namespace std;

typedef pair<int, int> PII;
int main()
{
	cin.tie(0);
	int T;
	cin>>T;
	while(T--)
	{
		int n;
		cin>>n;
		vector<int> a(n);
		for(int i=0; i<n; i++) cin>>a[i];
		
		if(n == 1) cout<<0<<endl;
		else 
		{
			int cnt = 0;
			vector<int> l(n), r(n); 
			int idx = 0;
			int x = 0;
			for(int i=1; i<n; i++)
				if((a[0]+a[i])%2 == 0) //找到最后一个与第一个相同奇偶性的下标 
					x = i;
			for(int i=0; i<x; i++)  //不是i<n,是i<x,所有x之前的
				if((a[x]+a[i])%2 == 0)
				{
					a[i] = a[x];  //将于所有与第一个元素相同奇偶性的数改变成a[x] 
					l[idx] = i, r[idx++] = x;
					cnt++;
				}
			for(int i=1; i<n; i++)
				if((a[0]+a[i])%2 == 1) 
				{
					a[i] = a[0];  //将于所有与第一个元素不相同奇偶性的数改变成a[x] 
					l[idx] = 0, r[idx++] = i;
					cnt++;
				}
			 cout<<cnt<<endl;
			 for(int i=0; i<cnt; i++)
				printf("%d %d\n", l[i]+1, r[i]+1);	
		}
	}
	return 0;
}

第13题Meeting on the Line (1600)

标签:二分、贪心、执行、数学、三分搜索

//一定要注意:本题不是让所有人的时间最小,而是让最大值最小 
//如果所有t=0,就是一个经典的问题,答案就是:就是最大和最小坐标的平均值
//我们可以把t加入到x中来将问题转化成这个经典问题:
/*
将(xi, ti)转化成(xi-ti, 0)和(xi+ti, 0) 

然后遍历所有i,找出最小的xi-ti,就变成了转化后的最小位置 
同理,找出最大的xi+ti,就变成了转化后的最大位置 
*/
#include<bits/stdc++.h>
using namespace std;

const int inf = 1e9;
const int N = 200010;

int s[N];

void solve()
{
	int n;
	cin>>n;
	vector<int> x(n), t(n);
	for(int i=0; i<n; i++) cin>>x[i];
	int mi = inf, mx = -inf;
	for(int i=0; i<n; i++)
	{
		cin>>t[i];
		mi = min(mi, x[i] - t[i]);
		mx = max(mx, x[i] + t[i]);
	}
	printf("%.7lf\n", (double)(mi+mx)/2);  //要求小数点后6位 
}
int main()
{
	int T;
	cin>>T;
	while(T--)
	{
		solve();
	}
	return 0;
}

第14题Reset K Edges(1900)

标签:二分、dfs、图论、贪心、树

本题做法就是二分,遇到深度为mid-1的就割掉
//实现方式一:用dfs求子树深度
#include<bits/stdc++.h>
using namespace std;
int n, k;
vector<int> edge[200010];
int step;
int mid;

int dfs(int u, int fa)
{
	int depth = 0;
	for(int i=0; i<edge[u].size(); i++)
	{
		int v = edge[u][i];
		int de = dfs(v, u);
		depth = max(depth, de+1);
	}
	if(u > 1 && depth == mid-1) //当这课树的深度为depth-1,那么这棵树就和父节点的边割掉,例如:4变成2和1 
	{
		if(fa != 1) step++;  //和根节点无论怎么割深度都是1 
		return -1;  //和+1相加变成0,也就是舍弃这个子树了 
	}
	else 
		return depth;
}
bool check()
{
	step = 0;
	dfs(1, 0);
	return step <= k;
} 
void solve()
{
	cin>>n>>k;
	for(int i=1; i<=n; i++) edge[i].clear();
	for(int i=2; i<=n; i++) 
	{
		int x;
		scanf("%d", &x);
		edge[x].push_back(i);
	}
	
	int l = 1, r = n-1;   //高度范围是[1, n-1] 
	while(l < r)
	{
		mid = l + r >> 1;	
		if(check()) r = mid;
		else l = mid+1;
	}
	cout<<l<<endl;
}
int main()
{
	int T;
	cin>>T;
	while(T--)
	{
		solve();
	}
	return 0;
}


//实现方式二:从下往上构建树
#include<bits/stdc++.h>
using namespace std;

void solve()
{
	int n, k;
	cin>>n>>k;
	vector<int> p(n+1);
	for(int i=2; i<=n; i++)
		cin>>p[i];
	
	int l = 1, r = n-1;   //高度范围是[1, n-1] 
	while(l < r)
	{
		int mid = l + r >> 1;	
		int step = 0;
		vector<int> h(n+1);
		for(int i=n; i>=2; i--)
		{
			if(h[i]==mid-1 && p[i]!=1)  //p[i]!=1:和根节点无论怎么割深度都是1  //当这课树的深度为mid-1,那么这棵树就和父节点的边割掉,例如:4变成2和1 
				step++;
			else 
				h[p[i]] = max(h[p[i]], h[i]+1);
		}
		if(step <= k) r = mid;
		else l = mid+1;
	}
	cout<<l<<endl;
}
int main()
{
	int T;
	cin>>T;
	while(T--)
	{
		solve();
	}
	return 0;
}

第15题​​​​​​​Phase Shift(1400)

标签:dfs、dsu、图标、贪心、字符串


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

vector<int> c(26, -1);  //被谁指 
vector<int> fc(26, -1);  //指向谁
vector<int> sz(26, 1);   //当前链的字符个数 
vector<int> p(26);  //当前链的祖字符 
int find(int x)
{
	if(x != p[x]) p[x] = find(p[x]);
	return p[x];
}
void solve()
{
	int n;
	cin>>n;
	string s;
	cin>>s;
	for(int i=0; i<26; i++) 
	{
		c[i] = -1;
		fc[i] = -1;
		sz[i] = 1;
		p[i] = i;
	}
	
	for(int i=0; i<n; i++)
	{
		int t = s[i]-'a';
		if(c[t] == -1) 
		{
			for(int j=0; j<26; j++)
				if(fc[j]==-1 && (find(j)!=find(t) || sz[t]==26))
				{
					c[t] = j;
					fc[j] = t;
					p[t] = find(j);
					sz[find(j)] += sz[t];
					break;
				}
		}
		printf("%c", c[t]+'a');
	}
	cout<<endl;
}
int main()
{
	int T;
	cin>>T;
	while(T--)
	{
		solve();
	}
	return 0;
}

第16题​​​​​​Good Subarrays (Easy Version)(1300)

标签:二分、数据结构、双指针

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

typedef long long LL;
void solve()
{
	int n;
	cin>>n;
	vector<int> a(n);
	for(int i=0; i<n; i++) cin>>a[i];
	
	LL res = 0;
	int l = 0; 
	for(int r=0; r<n; r++)
	{
		l = max(l, r-(a[r]-1));  //主要就是这里  //取max是因为l只能增大 
		res += r-l+1;
//		printf("l:%d r:%d res:%lld\n", l, r, res);
	}
	cout<<res<<endl;
}
int main()
{
	int T;
	cin>>T;
	while(T--)
	{
		solve();
	}
	return 0;
}

第17题​​​​​​Coprime(1100)

标签:暴力、贪心、数论

第一种实现方式
#include<bits/stdc++.h>
using namespace std;

typedef long long LL;

vector<int> p[1010];  
void solve()
{
	int n;
	cin>>n;
	vector<int> id[1010];
	for(int i=1; i<=n; i++)
	{
		int x;
		cin>>x;
		id[x].push_back(i);  //存入每个数出现的下标 
	}
	
	int res = -1;
	for(int i=1; i<=1000; i++)
		if(!id[i].empty())
			for(int j : p[i])
				if(!id[j].empty())
					res = max(res, id[i].back()+id[j].back());  //取下标最大的两个 

	cout<<res<<endl; 
}
int main()
{
	for(int i=1; i<=1000; i++)
		for(int j=1; j<=1000; j++)
			if(__gcd(i, j) == 1)  //直接调用自带的:__gcd() 
				p[i].push_back(j);  //预处理出来互为质数的两个数 
				
	int T;
	cin>>T;
	while(T--)
	{
		solve();
	}
	return 0;
}

/第二种方式/
#include<bits/stdc++.h>
using namespace std;

typedef long long LL;

int gcd(int a, int b)
{
	return b ? gcd(b, a%b) : a;
}
void solve()
{
	int n;
	cin>>n;
	vector<int> id(1010, 0);
	for(int i=1; i<=n; i++) 
	{
		int x;
		cin>>x;
		id[x] = i;  //存储每个数最大的下标 
	}
	int res = -1;
	for(int i=1; i<=1000; i++)
		for(int j=1; j<=1000; j++)
			if(gcd(i, j)==1 && id[i]!=0 && id[j]!=0)
				res = max(res, id[i]+id[j]);
	
	cout<<res<<endl;
}
int main()
{
	int T;
	cin>>T;
	while(T--)
	{
		solve();
	}
	return 0;
}

第18题​​​​​​​​​​​​​Smaller(1500)

标签:构造算法、贪心、字符串

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N = 10;

void solve()
{
	bool sta = false, stb = false;  //a,b字符串中是否存在>'a'的字符 
	LL cnta = 0, cntb = 0;  //=='a'的字符数量  //可能会爆int 
	int q;
	cin>>q;
	while(q--)
	{
		int d, k;
		string x;
		cin>>d>>k>>x;
		
		for(auto c : x)
		{
			if(d == 1)
			{
				if(c > 'a') sta = true;
				else cnta += k;
			}
			else 
			{
				if(c > 'a') stb = true;
				else cntb += k;
			}
		}
		if(stb)  //b字符串中有>'a'的字符,则a<b
			puts("YES");  
		else if(!sta && cnta<cntb)  //b中全是'a',那么就比较a和b中的'a'的数量(且前提是a中也全是'a') 
			puts("YES");
		else 
			puts("NO");
	}
}
int main()
{
	int T;
	cin>>T;
	while(T--)
	{
		solve();
	}
	return 0;
}

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值