题意:
给定一个长度为10^6的数n,问能不能把这个数分成两半,使它的前一半组成的数被整数a整除,后一半组成的数被整数b整除,a,b小于10^8,且要求分成的数不能有前导0.
题解:
字符串a记录大数n.
大数取模的板子改进一下即可,用一个xzero[i]数组记录a[0]到a[i]组成的数对a取模是否为0.
然后将大数取模逆过来写一遍,用一个yzero[i]数组记录a[len-1]到a[i]组成的数对b取模是否为0.
最后从0到len-1跑一遍xzero和yzero数组,如果有一个位置i满足xzero[i]=1以及yzrero[i+1]=1,那么这个位置分割下来的数就符合,输出即可。
这个题一开始只正向取模去做了一次,然后跑循环对后面部分在跑一次正向取模,超时了 。然后想到能不能逆向取模跑一下,但是考虑到幂每次乘10太大了,不敢写。结束后队友过了,用的就是我想的思路,我才想到可以每次都对幂取模啊。唉,理解还是不到位吧,每次都差一点。取模的式子当中的每一项可以先单独取模一下(不包括分母),这点还是没能活学活用。
代码:
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
const int maxn=1e6+5;
char a[maxn];
bool xzero[maxn];
bool yzero[maxn];
int main()
{
scanf("%s", a);
int x, y;
scanf("%d%d", &x, &y);
int mod=0;
int i, j;
int len=strlen(a);
for(i=0; i<len-1; i++) // 正向取模
{
mod=(mod*10+a[i]-'0')%x;
if(mod==0 && a[i+1]!='0')xzero[i]=1;
}
int ten=1;
mod=0;
for(i=len-1; i>0; i--) // 逆向取模
{
ten%=y;
if(a[i]=='0')
{
ten*=10;
ten%=y;
continue;
}
mod=(mod+ten*(a[i]-'0'))%y;
if(mod==0)yzero[i]=1;
ten*=10;
}
for(i=0; i<len-1; i++)
{
if(xzero[i]&&yzero[i+1])
{
printf("YES\n");
for(j=0; j<=i; j++)printf("%c", a[j]);
printf("\n");
for(; a[j]; j++)printf("%c", a[j]);
printf("\n");
break;
}
}
if(i>=len-1)printf("NO\n");
return 0;
}