回文串_结论_字符串模拟_跳出循环_码力_1883_B. Chemistry

#include

using namespace std;

const int N=1e5+10;

char a[N];
int cnt[30];

void solve()
{
	int n,k;
	cin>>n>>k;
	
	for(int i=0;i<n;i++)
		cin>>a[i];
	
	for(int i=0;i<n;i++)
		cnt[a[i]-'a']++;
	
	while(k)
	{
		for(int i=0;i<26;i++)
			if(cnt[i]%2!=0)
				k-=1,cnt[i]-=1;
		
		for(int i=0;i<26;i++)
			while(cnt[i]>0)
				k-=cnt[i],cnt[i]=0;
		
		
	}
	
	int cnt_odd=0;
	for(int i=0;i<26;i++)
		if(cnt[i]%2!=0)
			cnt_odd++;
	
	if(cnt_odd>1)
		cout<<"NO"<<endl;
	else
		cout<<"YES"<<endl;
	
	for(int i=0;i<26;i++)
		cnt[i]=0;
}

int main()
{
	ios::sync_with_stdio(false);
	cin.tie(nullptr);
	
	int t;
	cin>>t;
	
	while(t--)
		solve();
	
	return 0;
}

写成上面这样子写不下去了,码力太弱了

实现不了自己想的

回文串,就是要求,除了一个字母出现次数可以是奇数,其他字母出现次数都要是偶数

所以可以先把字母的出现次数统计出来,然后把出现次数是奇数的字母减去一个,就变成偶数了,然后从头开始减,写到这里发现可以用计数器里面的字母出现次数减去要求删除的字符数目

#include

using namespace std;

const int N=1e5+10;

char a[N];
int cnt[30];

void solve()
{
	int n,k;
	cin>>n>>k;
	
	for(int i=0;i<n;i++)
		cin>>a[i];
	
	for(int i=0;i<n;i++)
		cnt[a[i]-'a']++;
	
	while(k)
	{
		for(int i=0;i<26;i++)
			if(cnt[i]%2!=0)
				k-=1,cnt[i]-=1;
		
		for(int i=0;i<26;i++)
			if(k-cnt[i]>=0)
			{
				k-=cnt[i];
				cnt[i]=0;
			}
			else
			{
				cnt[i]-=k;
				k=0;
			}
	}
	
	int cnt_odd=0;
	for(int i=0;i<26;i++)
		if(cnt[i]%2!=0)
			cnt_odd++;
	
	if(cnt_odd>1)
		cout<<"NO"<<endl;
	else
		cout<<"YES"<<endl;
	
	for(int i=0;i<26;i++)
		cnt[i]=0;
}

int main()
{
	ios::sync_with_stdio(false);
	cin.tie(nullptr);
	
	int t;
	cin>>t;
	
	while(t--)
		solve();
	
	return 0;
}

但是还是过不了样例

#include

using namespace std;

const int N=1e5+10;

char a[N];
int cnt[30];

void solve()
{
	int n,k;
	cin>>n>>k;
	
	for(int i=0;i<n;i++)
		cin>>a[i];
	
	for(int i=0;i<n;i++)
		cnt[a[i]-'a']++;
	
	while(k)
	{
		for(int i=0;i<26;i++)
			if(cnt[i]%2!=0)
			{
				k-=1,cnt[i]-=1;
				if(k<=0)
					break;
			}
		
		for(int i=0;i<26;i++)
			if(k-cnt[i]>=0)
			{
				k-=cnt[i];
				cnt[i]=0;
			}
			else
			{
				cnt[i]-=k;
				k=0;
			}
	}
	
	int cnt_odd=0;
	for(int i=0;i<26;i++)
		if(cnt[i]%2!=0)
			cnt_odd++;
	
//	cout<<"字母的出现次数是奇数,这样的字母的种类数目:"<
//	cout<
	
	if(cnt_odd>1)
		cout<<"NO"<<endl;
	else
		cout<<"YES"<<endl;
	
	for(int i=0;i<26;i++)
		cnt[i]=0;
}

int main()
{
	ios::sync_with_stdio(false);
	cin.tie(nullptr);
	
	int t;
	cin>>t;
	
	while(t--)
		solve();
	
	return 0;
}

改成上面这样,样例过了

最后也ac

该题是一个div 3的第二题,九百分,说明我的实力可能现在确实只是这个水平,还得多加练习

之前过不了样例的主要原因是等到while里面第一个for循环结束的时候才判断k的数值,事实上可能在过程中k的数值就小于0了,所以加上一个判断,只要小于等于零,就及时跳出循环

看了一下正解,发现是我写的太复杂了,不需要模拟这个减去的过程,只需要找到数学上的公式来判断即可

不然写这么长,肯定难以短时间内把代码敲出来

假设把出现次数为奇数次的字母的种类数目,假设数目是等于0的,表示不需要删除,但是题目要求恰好删除k个字母,其实是一定可以做到的,每一次删两个一样的就行,假设k是奇数,最后删一个就行,回文串中间可以是奇数个字母,但是两边必须是对称的,两边的字母的个数加起来一定是偶数个

奇数个字母的,删除一个字母就可以变成偶数个字母

最后需要剩下的是,字母数目是偶数个的字母,最多剩下一种(注意这个量词,种),字母个数是奇数个的字母

比如说有4种字母的出现次数都是奇数,那么至少需要删除3个字母才可以变成回文串

那么删除次数和3之间的关系就是大于等于3,k>=x-1x表示的是出现次数是奇数的字母的种类数目

#include

using namespace std;

const int N=1e5+10;

char a[N];
int cnt[30];

void solve()
{
	int n,k;
	cin>>n>>k;
	
	for(int i=0;i<n;i++)
		cin>>a[i];
	
	for(int i=0;i<n;i++)
		cnt[a[i]-'a']++;
	
	int cnt_odd=0;
	for(int i=0;i<26;i++)
		if(cnt[i]%2!=0)
			cnt_odd++;
	
	if(k>=cnt_odd-1)
		cout<<"YES"<<endl;
	else
		cout<<"NO"<<endl;
	
	for(int i=0;i<26;i++)
		cnt[i]=0;
}

int main()
{
	ios::sync_with_stdio(false);
	cin.tie(nullptr);
	
	int t;
	cin>>t;
	
	while(t--)
		solve();
	
	return 0;
}

总结就是不要傻乎乎模拟过程,先看一下能不能猜出结论

你可能感兴趣的:(#,CF,900-1000,算法,数据结构,图论)