D:
本题正规解法为 深搜+状态压缩
当然,本人并没有使用这种方法,本人选择的是 贪心策略 。
程序如下:
#pragma GCC optimize(2) //O2优化(比赛禁用)
#include<iostream>
#include<cstring>
#include<string>
#include<cstdio>
#include<cmath>
#include<algorithm>
using namespace std;
int n;
int mapn[30][27];
int mapall[27];
int main()
{
cin>>n;
for(int i=1;i<=n;i++)
{
char ch[100001];
cin>>ch;
int l=strlen(ch);
for(int j=1;j<=l;j++)
{
if(mapn[i][ch[j-1]-'a'+1]+1>=2) mapn[i][ch[j-1]-'a'+1]=0;
else mapn[i][ch[j-1]-'a'+1]++;
mapall[ch[j-1]-'a'+1]++;
}
}
int g=0;
for(int i=1;i<=26;i++)
{
if(mapall[i]%2==1) g++;
}
if(g==0)
{
cout<<n<<endl;
for(int k=1;k<=n;k++)
{
cout<<k<<' ';
}
return 0;
}
int maxn=-1,num=0,v=0,w=0;
int t;
for(t=n;t>=1;t--)
{
maxn=-1;
for(int i=1;i<=n;i++)
{
if(mapn[i][0]==0)
{
v=0,w=0;
for(int j=1;j<=26;j++)
{
if((mapall[j]-mapn[i][j])%2==0) v++;
else w++;
}
if(maxn<v)
{
maxn=v;
num=i;
}
if(w==0)
{
cout<<t-1<<endl;
mapn[i][0]=1;
for(int k=1;k<=n;k++)
{
if(!mapn[k][0]) cout<<k<<' ';
}
return 0;
}
}
}
mapn[num][0]=1;
for(int i=1;i<=26;i++)
{
mapall[i]-=mapn[num][i];
}
}
}
我写这个程序的时候,根本都不知道我在写的是什么
写法解读:
读入字符串,储存到 mapn[i][j] 里
当然并不是直接存放,而是记录下各个字母所出现的个数。
for(int i=1;i<=n;i++)
{
char ch[100001];
cin>>ch;
int l=strlen(ch);
for(int j=1;j<=l;j++)
{
if(mapn[i][ch[j-1]-'a'+1]+1>=2) mapn[i][ch[j-1]-'a'+1]=0;
else mapn[i][ch[j-1]-'a'+1]++;//mapn[i][j]储存第i个字符串中第j个字母出现的次数(字典顺序)
mapall[ch[j-1]-'a'+1]++; //储存全部字符串中各个字母出现次数
}
}
但直接++也是太暴力了,本人选择加上小处理,如上红色代码段
因为本题要使同个字母出现个数成偶数,所以本人把在同个字符串里凑成对的字母的出现次数直接归为 0
让mapn[i][j]里只有0和1,方便处理
特殊处理,如果全部字母的出现次数都为偶数,直接输出就行了
for(int i=1;i<=26;i++)
{
if(mapall[i]%2==1) g++;
}
if(g==0)
{
cout<<n<<endl;
for(int k=1;k<=n;k++)
{
cout<<k<<' ';
}
return 0;
}
三层循环,数据范围小,无所畏惧
int maxn=-1,num=0,v=0,w=0;
int t;
for(t=n;t>=1;t--) //循环1
{
maxn=-1;
for(int i=1;i<=n;i++) //循环2
{
if(mapn[i][0]==0)
{
v=0,w=0;
for(int j=1;j<=26;j++) //循环3
{
if((mapall[j]-mapn[i][j])%2==0) v++; //记录奇或偶数的出现次数
else w++;
}
if(maxn<v) //选择更接近(出现次数)全部偶数的字符串
{
maxn=v;
num=i;
}
if(w==0) //当没有奇数情况出现
{
cout<<t-1<<endl;
mapn[i][0]=1;
for(int k=1;k<=n;k++)
{
if(!mapn[k][0]) cout<<k<<' ';
}
return 0;
}
}
}
mapn[num][0]=1; //更改标签
for(int i=1;i<=26;i++) //更新mapall的值
{
mapall[i]-=mapn[num][i];
}
}
揭露 map[i][0] 的功能:记录字符串是否被使用,0为“否”,1为“是”
循环(1):for(t=n;t>=1;t--)
意义:保留 t -1个字符串
循环(2):for(int i=1;i<=n;i++)
意义:枚举到第i个字符串
循环(3):for(int j=1;j<=26;j++)
意义:26个字母中第j个字母(字典顺序)
综上,很容易发现,本人的思路是:
记录字母出现的总次数,用 所有字符串字母出现次数的总数 去减 一个字符串中字母出现的次数,得出的差再与减去其他字符串得出的差比较,看哪个出现次数为偶数的情况多就删除哪个。(此处比较难理解,用心总会明白的)
补充:变量v、w,分别用于记录剩下字符串中出现次数为偶数、奇数的字母的个数
[ The End. ]