MG loves apple
MG是一个财富爆表的男孩子。他拥有N(1<=N<=100000)个苹果,每个苹果上标有一个数字0~9,代表它的价值。 一个合法的数字是不含有前导零的,这n个苹果恰好排成了一个合法的N位数。 MG拥有拿去K个苹果的权利(0<=K<N)。 他想知道是否存在方案,使得恰好拿去K个苹果后,序列中剩下的苹果排成的合法数字模3等于零。数据保证所有N之和不超过1000000. MG认为这件事非常容易,不屑于用计算机解决,于是运用他高超的人类智慧开始进行计算。作为一名旁观者,你也想挑战MG智慧,请你写个程序,计算答案。
第一行一个整数T,代表数据组数(1<=T<=60)。 接下来,对于每组数据—— 第一行两个个整数N,K,表示苹果序列长度,以及需要拿去的苹果个数. 接下来一行N个整数X,表示每个苹果的价值(0<=X<=9)。
对于每一组数据,输出一行。 若方案存在,则输出“yes”,否则输出“no”。(输出不包含引号)
2 5 2 11230 4 2 1000
yes no
官方题解写的方法就很好。。。。
我们设S0、S1、S2分别为原串上mod3=0、1、2数字的个数。 我们假定删除取模后为0、1、2的数字各A、B、C个,则显然有0<=A<=S0,0<=B<=S1,0<=C<=S2且K=A+B+C且Sum mod3=(A∗0+B∗1+C∗2)mod3=(S0∗0+S1∗1+S2∗2)mod3=bias。 枚举C的值,我们可得Bmod3=(bias−C∗2)mod3,A=K−B−C。如果有若干组A,B不逾界,可知这些(A,B,C)是在模意义下合法的解,但不一定满足没有前导零。
所以,对于【大于0的数】我们贪心地从后往前删除,对于0我们贪心地从前往后删除。
需要统计出:a3=第一个【mod3=0且非0的数】前0的个数(如果mod3=0且非0的数不存在,那么a3就取所有零的个数),E1=【第一个0前是否存在mod3=1的数】,E2=【第一个0前是否存在mod3=2的数】。
则以下情况满足任一种都能保证无前导零:A>=a3。B<S1且E1。C<S2且E2。
不过要加一个特判,当删n-1个时,留一个0是可以的
当时很不理解为什么满足“A>=a3。B<S1且E1。C<S2且E2。”其中之一就一定成立
后来举了好多例子,发现确实是
这里假设0为等于零的数,1为模三等于1的数,2为模三等于2的数,3为模三等于3且非零的数
最开始数为合法数字
第一位肯定是1或2或3
是3时,要么把0,3全部删掉,这样肯定不会有前导零,要么不全删,这样我只要保留第一个3就不会出现前导零
所以是3时,肯定不会出现前导零的情况,而第一位是3一定满足A>=a3的条件
是2时,不全删,保留第一个2,肯定不会出现前导零,这个时候满足c<s2的条件
全删掉时,只有当“A>=a3。B<S1且E1”至少有一个条件成立时就不会出现前导零,否则就会出现
是1时同理
#include<bits/stdc++.h>
using namespace std;
int num[100005];
int main()
{
int z,t,n,k,i,j,xx[3];
char c;
scanf("%d",&t);
while(t--)
{
i=0;
scanf("%d %d",&n,&k);
getchar();
xx[0]=xx[1]=xx[2]=0;
int sum=0;
int flog=0,flag=0,zero=0,flag1=0,flag2=0;
for(i=0;i<n;i++)
{
c=getchar();
num[i]=c-'0';
if(num[i]%3==0&&!flog)
{
if(num[i]==0)
{
zero++;
flag=1;
}
else
flog=1;
}
if(!flag)
{
if(num[i]%3==1)
flag1=1;
else if(num[i]%3==2)
flag2=1;
}
sum=(sum+num[i])%3;
xx[num[i]%3]++;
}
bool ok=0;
if(k==n-1)
{
for(i=0;i<n;i++)
if(num[i]%3==0)
ok=1;
if(ok)
printf("yes\n");
else
printf("no\n");
continue;
}
for(i=0;i<=xx[2];i++)
{
for(j=((sum-i*2)%3+3)%3;j<=xx[1];j+=3)
// for(j=0;j<=xx[1];j++)
{
// if((i*2+j*1)%3==sum)
// {
z=k-i-j;
if(z<=xx[0]&&z>=0)
{
if(z>=zero)
ok=1;
if(j<xx[1]&&flag1)
ok=1;
if(i<xx[2]&&flag2)
ok=1;
if(ok)
break;
}
// }
}
if(ok)
break;
}
if(ok)
printf("yes\n");
else
printf("no\n");
}
return 0;
}