大意:
把一个字符串s分割成m个串,这m个串满足至多有一种字符出现次数为奇数次,其他均为偶数次,问m的最小值
思路:
一开始看错了题意,以为是可以任意重排字符串,然后刷刷敲完之后死活过不去。。。
字符串顺序是不能改变的。那么这里可以用一个状压的思路。用f[i](1到26的一个01串对应的大小)来代表从1到i的每一个字母的数量(奇数为1,偶数为0)
则区间[l, r]可以加一个子串,就是a[l]^a[r]的值必须为2的幂次(也就是中间只有一个奇数次数的字母)。
然后用dp来对每一个状态进行推导。
如果某一状态本身=0,说明里面全是偶数,则其dp值=1;
如果某一个状态只有一位为1,说明里面只有一个奇数,其dp值也应该=1,这一定最优
另外考虑其它状态,就枚举每一位进行转移就好了。
for(int j=0;j<26;++j)
{
//cout<<dp[f[i]]<<' '<<dp[f[i]^(1<<j)]<<endl;
dp[f[i]]=min(dp[f[i]],(ll)dp[f[i]^(1<<j)]+1);
}
code:
#include<bits/stdc++.h>
using namespace std;
#define ll int
#define endl '\n'
const ll N=2e5+100;
string s;
ll f[N];
ll dp[(1<<26)];//对应状态的最优解
bool ff(ll x)//对应状态
{
if(x==0)
{
dp[x]=1;
return 1;
}
for(int i=0;i<26;++i)
{
if((x^(1<<i))==0)
{
dp[x]=1;
return 1;
}
}
return 0;
}
int main()
{ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
cin>>s;
ll ans=0;
for(int i=0;i<s.size();++i)
{
ans^=(1<<(s[i]-'a'));
f[i]=ans;
}
//for(int i=0;i<s.size();++i) cout<<f[i]<<' ';
memset(dp,0x3f,sizeof dp);
//dp[0]=0;
for(int i=0;i<s.size();++i)
{
if(ff(f[i])) continue;//判断是否全是偶数
for(int j=0;j<26;++j)
{
//cout<<dp[f[i]]<<' '<<dp[f[i]^(1<<j)]<<endl;
dp[f[i]]=min(dp[f[i]],(ll)dp[f[i]^(1<<j)]+1);
}
}
cout<<dp[f[s.size()-1]];
return 0;
}