——切记:不要去想是否做过类似题,那样易导致思维混乱。无论遇到什么样的题,都是由基础变化而来,所以如何把题倒回去才是最重要的。
题解:
不管是26进制还是10进制数,计算方法是一样的
例如:
954(26进制)=9*26^2+5*26+4
954(10进制)=9*10^2+5*10+4
如果是x进制,只需要预处理一个x的幂数即可。
所以是几进制无所谓。
重点:交换后如何快速得到一个新数,重新来一遍循环太浪费时间,O(1)的时间其实就可以做到。
举个例子:954%3【954是一个十进制数,为了符合日常习惯】
首先得到ans=954%3
如何得到:(9*100+5*10+4)%3
暂时不要去考虑非常大的数,等一下会说如何处理。
——现在想让9和4交换,再次%3,如何做到?
只需ans=[ans-(900+4)%3+(400+9)%3]%3。
请仔细看下面这个等式。
459%3
=(954-(900+4)+(400+9))%3
=[954%3-(900+4)%3+(400+9)%3]%3
该式子是满足加减取模定理的
因此O(1)时间就可得到新的结果。
现在考虑大数:
预处理的幂数,很容易就爆long long的:
其实乘法也满足取模定理
预处理时不断取模即可
例如:
94%3
未预处理幂数:10 1
预处理后幂数:1 1
(9*10+4)%3=(9*1+4)%3
拓展:改变某位数字依旧先减后加,O(1)
代码:
#include<bits/stdc++.h>
using namespace std;
const int N=2e3+10;
int n,m,k;
char str[N];
int a[N],s[N],p[N];
bool check(int l,int r,int ans)
{
ans-=a[l]*p[l]%m;//先减
ans-=a[r]*p[r]%m;
ans+=a[l]*p[r]%m;//再加
ans+=a[r]*p[l]%m;
ans=(ans%m+m)%m;//再取模
return ans==0;
}
void solve()
{
scanf("%s %d",str+1,&m);
n=strlen(str+1);
//预处理幂数
p[n]=1;
for(int i=n-1;i>=1;i--)
p[i]=p[i+1]*26%m;
//预处理:把字符转化为对应数字
for(int i=1;i<=n;i++)
a[i]=(str[i]-'A')%m;
int ans=0;
for(int i=1;i<=n;i++)
ans=(ans+a[i]*p[i]%m)%m;
if(ans==0)
{
printf("0 0\n");
return;
}
for(int l=1;l<=n;l++)
{
for(int r=l+1;r<=n;r++)
{
if(check(l,r,ans))
{
printf("%d %d\n",l,r);
return;
}
}
}
printf("-1 -1\n");
return;
}
int main()
{
int T=1;
while(T--) solve();
return 0;
}