【acm备赛day2】思维专题(E - G)

目录

E. Sequence Master - 思维 + 找规律

F. Peculiar Movie Preferences - 1700 - 构造 + 思维 + 哈希表

G. Say No to Palindromes - 1600 - 前缀和 + 思维 + 找规律


E. Sequence Master - 思维 + 找规律

Problem - 1806C - Codeforces

题目:

  • 我们定义一个长度为2m的集合为好集合,当且仅当:该集合的任意长度为m的子集合S,满足在S中的元素之积=不在S中的元素之和
  • 我们给定一个长度为2n的数组a,需要构造一个长度为2n的好集合b,使ab距离尽可能小
  • 输出a,b数组的最短距离,定义最短距离为:

思路:

注意要long long!!!

ans开到1e18

首先枚举几个好集合,会发现能满足好集合条件的集合非常少

  • m=1时,{0,0}{1,1}……{x,x}
  • m=2时,{0,0,0,0}{2,2,2,2}{-1,-1,-1,2}
  • m=3时,{0,0,0,0,0,0}
  • m=4时,{0,0,0,0,0,0,0,0}{-1,-1,-1,-1,-1,-1,-1,4}

易得规律为:

首先对应所有m值,都有好集合{0,0……0},先全部计算差值

  • m=1时,可以选无数种相等的两个数,为了让ab两集合差值最小,即就是只变一个数,因此res=max(a[1],a[2])-max(a[1],a[2])
  • eg:[6,9]——[6,6]   res=9-6=3
  • m=2时,可以用{2,2,2,2}和{-1,-1,-1,2}两种构造方式构造,都遍历一下,求个最小值
  • m为偶数时,好集合还有一种形式{-1,-1,-1……-1,x}
  • m为奇数时,无解
#include <iostream>
#include <cstring>
#include <algorithm>
#include <queue>
#include <map>
#include <set>
#include <vector>
#include <cmath>
#include <deque>
#include <unordered_map>
#define pb push_back
#define int long long
#define INF 0x3f3f3f3f
#define x first
#define y second
#define all(v) (v).begin(),(v).end()
#define PII pair<int,int>
#define io ios_base::sync_with_stdio(false), cin.tie(nullptr), cout.tie(nullptr)
using namespace std;

const int N=2e6+10;
int a[N];

void solve()
{
	int n,res=0,ans=1e18;
	cin>>n;
	//先把{0,0……0}的情况处理 
	for(int i=1;i<=2*n;i++) cin>>a[i],res+=abs(a[i]-0);
	ans=min(ans,res);
	
	if(n==1)
	{
		res=0;
		res=max(a[1],a[2])-min(a[1],a[2]);
		ans=min(ans,res);
	}
	if(n==2)
	{
		res=0;
		for(int i=1;i<=2*n;i++) res+=abs(a[i]-2);
		ans=min(ans,res);
	}
	if(n%2==0)
	{
		res=0;
		for(int i=1;i<=2*n;i++) res+=abs(a[i]-(-1));
		//看用哪个当x操作数最小 
		for(int i=1;i<=2*n;i++) 
		{
			int t=res-abs(a[i]-(-1))+abs(a[i]-n);
			ans=min(ans,t); 
		} 
	}
	cout<<ans<<endl;
} 

signed main()
{
	io;
	int t;
	cin>>t;
	while(t--)
		solve();
	return 0;
}

F. Peculiar Movie Preferences - 1700 - 构造 + 思维 + 哈希表

Problem - 1628B - Codeforces

题意:

给n个长度不超过3的字符串,可以选择若干个字符串进行拼接(选择的字符串内顺序不变),问是否可以组合出回文串?

思路:

对于n个字符串,如果其中出现过回文串,则直接输出yes,一个字母也是一个回文串

因为长度不超过3,因此只存在长度为2和3的字符串,先考虑多个字符串拼接情况,如果s1,s2,s3……sk能组合成回文串,则由于回文串的性质可知,只取头尾s1和sk也可以组成字符串

因此只需要考虑两个字符串组合的情况,则有2+2,2+3,3+2,3+3四种情况

  • 对于2+2和3+3这种字符串,只要枚举到某字符串s时,查询map内是否存在逆序串s'即可
  • 对于2+3字符串s,枚举到长度为3的字符串时,取s[2]+s[1]组成字符串在map中查询是否存在
  • eg:map[ab]=1,遍历到bac时,取s=ab
  • 对于3+2字符串s,枚举到长度为2的字符串时,s'=取s[1]+s[0] + a~z 26种字符中任意一种,map中查询是否存在s'
  • eg:map[abc]=1,遍历到ba时,当取s=ab+c时,存在,则输出yes
#include <iostream>
#include <cstring>
#include <algorithm>
#include <queue>
#include <map>
#include <set>
#include <vector>
#include <cmath>
#include <deque>
#include <unordered_map>
#define pb push_back
//#define int long long
#define INF 0x3f3f3f3f
#define x first
#define y second
#define all(v) (v).begin(),(v).end()
#define PII pair<int,int>
#define io ios_base::sync_with_stdio(false), cin.tie(nullptr), cout.tie(nullptr)
using namespace std;

const int N=1e5+10;
string s[N];

void solve()
{
	int n;
	cin>>n;
	unordered_map<string,bool> mp;
	for(int i=0;i<n;i++) cin>>s[i];
	for(int i=0;i<n;i++)
		if(s[i][0]==s[i][s[i].size()-1]) 
		{
			cout<<"YES"<<endl;
			return;
		}
	
	for(int i=0;i<n;i++)
	{
		if(s[i].size()==2)  //先枚举长度为2的字符串 
		{
			string t;
			t+=s[i][1]; t+=s[i][0];
			if(mp[t]) //判断2+2型 
			{
				cout<<"YES"<<endl;
				return;
			}
			for(char j='a';j<='z';j++)  //判断3+2型 
				if(mp[t+j])
				{
					cout<<"YES"<<endl;
					return;
				}
		}
		else  //枚举长度为3的字符串 
		{
			string t;
			t+=s[i][2]; t+=s[i][1];
			if(mp[t]||mp[t+s[i][0]])
			{
				cout<<"YES"<<endl;
				return;
			}
		} 
		mp[s[i]]=true;
	} 
	cout<<"NO"<<endl;
} 

signed main()
{
	io;
	int t;
	cin>>t;
	while(t--)
		solve();
	return 0;
}

G. Say No to Palindromes - 1600 - 前缀和 + 思维 + 找规律

Problem - 1555D - Codeforces

题意:

  • 美丽串定义为:该区间内不存在任何长度≥2的回文子串
  • 给一个仅包含a,b,c三种字符的长度为n的字符串,和m个询问,每次查询一个区间,问该区间内将子串修改为美丽串至少需要修改多少个字符

思路:

  • 美丽串如果起始为a,加一个b形成ab,此时不能加a也不能加b,只能形成abc,接下来也是不能加b和c,只能是abcabc循环
  • 其他的组合方式同理,bacbac……或cabcab,一共有【abc,acb,bac,bca,cab,cba】共六种基础串组合
  • 维护由第i种基础串构成美丽串时,需要修改字符的前缀和,最后把六种组合全部遍历一边,取最小值即可
  • f[i][j] —— 第i种基础串情况,前j个字符与原串对比的修改次数
#include <iostream>
#include <cstring>
#include <algorithm>
#include <queue>
#include <map>
#include <set>
#include <vector>
#include <cmath>
#include <deque>
#define pb push_back
//#define int long long
#define INF 0x3f3f3f3f
#define x first
#define y second
#define all(v) (v).begin(),(v).end()
#define PII pair<int,int>
#define io ios_base::sync_with_stdio(false), cin.tie(nullptr), cout.tie(nullptr)
using namespace std;

const int N=2e5+10;
int f[7][N];
string ch[7]={"","abc","acb","bac","bca","cab","cba"};
char s[N];

void solve()
{
	int n,m;
	cin>>n>>m;
	
	for(int i=1;i<=n;i++)
	{
		cin>>s[i];
		for(int j=1;j<=6;j++)
			f[j][i]=f[j][i-1]+(ch[j][(i-1)%3]!=s[i]);
		//i从1开始,(i-1)%3是为了对应ch字符串数组里相应的字符
		//如果s[i]与对应的美丽串模板不符,则该位修改值+1 
	}
	
	while(m--)
	{
		int l,r;
		cin>>l>>r;
		int res=INF;
		for(int i=1;i<=6;i++) 
			res=min(res,f[i][r]-f[i][l-1]);
		cout<<res<<endl;
	}
} 

signed main()
{
	io;
	/*int t;
	cin>>t;
	while(t--)*/ 
		solve();
	return 0;
}

猜你喜欢

转载自blog.csdn.net/weixin_61639349/article/details/129991931
g2o
G