NOIP2024T1
纪念第一道场切蓝题
第一眼读这题一直在想,这个限制的意义在哪?
想通这一点就好写了:因为无限次交换两个相邻字符就等于可以任意组合字符的排列顺序,所以为了给你提高难度加上了限制。这是可以手推的。
那么这样的话,我们发现每个
有了这个结论,我们考虑如何让匹配字符更多。
现在不考虑限制的情况,即假设两段字符串可以任意排列。
容易想到贪心法,我们尽可能将相同的字符排在一起,那么答案就是两段字符
有了限制怎么办捏?
根据结论,我们就会发现只是在上面那种情况的基础上多加了几段字符串!于是一个很自然的思路就出来了:我们尽可能让两段区间能够匹配相同字符,不能匹配了就换下一个区间继续匹配,文字解释或许不直观,看代码吧,注释很详细:
# include <stdio.h>
int main (void)
{
int T;
scanf ("%d",&T);
while(T)
{
char s1[100005];
char s2[100005];
char t1[100005];
char t2[100005];
int mch1[2];//第一个串的0/1的个数
int mch2[2];//第二个串的0/1的个数
mch1[0] = mch1[1] = mch2[0] = mch2[1] = 0;//初始化!考场因为这个调了1h
int n;
int ans=0;
scanf ("%d",&n);
scanf ("%s",s1);
scanf ("%s",s2);
scanf ("%s",t1);
scanf ("%s",t2);
int i=0,j=0;//限制(t中的0)的位置
int k=0;//已经确定的位置,即现在关注到第几个字符
while (k < n)
{
while (i < n && t1[i] == '1')//i是第一个串的
{
mch1[s1[i]-'0']++;//计数
i++;
}
while (j < n && t2[j] == '1')//j是第二个串的
{
mch2[s2[j]-'0']++;//计数
j++;
}
while (k < i && k < j) // 在限制之前字符可以任意排列,考虑这个情况
{
if (mch2[1] > 0 && mch1[1] > 0)//都有1,匹配1
{
mch1[1]--;
mch2[1]--;
ans++;
}
else if (mch2[0] > 0 && mch1[0] > 0)//都有0,匹配0
{
mch1[0]--;
mch2[0]--;
ans++;
}
k++;// 已经确定的位置过掉
}
if (k == n)//这里也是一个坑,不过看样例很容易调,s1[n]和s2[n]是相同的,在下面会多计一个数
{
break;
}
//这里要匹配一下不能交换的位置
if (i == j) //如果两个都不能交换
{
if (s1[i] == s2[j])//那么仅在它们相同时产生贡献
{
ans++;
}
mch1[0] = mch1[1] = mch2[0] = mch2[1] = 0;//换下一个区间了,之前一个区间的字符不能交换到这里来,清零重置
i++;
j++;
}
else if (i > j)//i!=j相当于某个区间还可以匹配下一个区间的字符,这里是j被限制
{
if (mch1[s2[j]-'0'] > 0)//如果这个不能交换的位置上的字符在第一个串上还有,就匹配它
{
mch1[s2[j]-'0']--;
ans++;
}
mch2[0] = mch2[1] = 0;//清零重置
j++;
}
else if (i < j)
{
if (mch2[s1[i]-'0'] > 0)//同理
{
mch2[s1[i]-'0']--;
ans++;
}
mch1[0] = mch1[1] = 0;
i++;
}
k++; // 又确认了一个位置
}
printf ("%d\n",ans);
T--;
}
}