目录
F. Peculiar Movie Preferences - 1700 - 构造 + 思维 + 哈希表
G. Say No to Palindromes - 1600 - 前缀和 + 思维 + 找规律
E. Sequence Master - 思维 + 找规律
题目:
- 我们定义一个长度为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 - 构造 + 思维 + 哈希表
题意:
给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 - 前缀和 + 思维 + 找规律
题意:
- 美丽串定义为:该区间内不存在任何长度≥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;
}