您的位置:首页 > 编程语言 > Go语言

Problem B. Sherlock and Watson Gym Secrets Google APAC 2017 University Test Round B

2017-02-02 20:50 1176 查看
这一题比赛时是懵逼的,直接暴力+快速幂过了小数据。

后来得知,因为mod的性质,(i^A)%K=(i%K)^A,所以只要枚举[0,K-1]的值就可以了。[K,N]范围内的i,mod之后结果和[0,K-1]中余数相同的i一样。

给定一个i值,[K,N]中相同余数的i的个数是i+mK<=N,m<=floor((N-i)/K)。注意要特判N<=K的case。

如果i对应的余数是modi,那么j对应的余数应该是K-modi,这样才能满足加起来mod K=0。

在枚举的时候可以记录i=j的个数,最后再从总的结果里减去余数=0对应的相等的个数即可。因为减去这个值之后ans可能变成负的,所以需要+mod在%mod。

#include<iostream>
#include<stdio.h>
#include<cstdio>
#include<string>
#include<cmath>
#include<stdlib.h>
#include<algorithm>
#include<string.h>
#include<cstring>
#include<vector>
#include<queue>
#include<map>

using namespace std;

//2017 RoundB Problem B. Sherlock and Watson Gym Secrets

const int maxn=100010;
int T;
const int mod=1000000007;
long long A;
long long B;
long long N;
long long K;
long long ans;
long long remA[maxn];
long long remB[maxn];
long long same[maxn];
long long pow_mod(long long a,long long b)
{
long long s=1;
long long t=1;
while(b)
{
if(b&t)
{
s=(s*a)%K;
}
a=(a*a)%K;
b=b>>1;
}
return s;
}
long long addremainnum(int num)
{
if(num==0)//i, j is positive, so exclude i=0
{
return (N-num)/K;//N/K + (N%K >= num)-1; this work for for(int i=0;i<K;i++) this excludes the case N<K
}
return (N-num)/K+1;//N/K + (N%K >= num);
}
int main()
{
freopen("B-large-practice.in","r",stdin);//
//freopen("input.txt","r",stdin);
freopen("output.txt","w",stdout);
scanf("%d",&T);
for(int ca=1;ca<=T;ca++)
{
scanf("%lld %lld %lld %lld",&A,&B,&N,&K);
ans=0;
memset(remA,0,sizeof(remA));
memset(remB,0,sizeof(remB));
memset(same,0,sizeof(same));
for(int i=0;i<min(N+1,K);i++)//if N<K, i=0 to N
{
long long powi=pow_mod(i,A)%K;
long long powj=pow_mod(i,B)%K;
remA[powi]+=addremainnum(i);
remA[powi]%=mod;
remB[powj]+=addremainnum(i);
remB[powj]%=mod;
long long powsum=(powi+powj)%K;//i=j
same[powsum]+=addremainnum(i);
same[powsum]%=mod;
//cout<<i<<" "<<powi<<" "<<powj<<" "<<powsum<<" "<<remA[powi]<<" "<<remB[powj]<<" "<<same[powsum]<<endl;
}
for(int powi=0;powi<K;powi++)
{
int powj=(K-powi)%K;
ans+=(remA[powi]%mod)*(remB[powj]%mod);
//cout<<ans<<endl;
ans%=mod;
}

ans-=same[0];//ans may become negative
ans+=mod;
ans%=mod;
printf("Case #%d: %lld\n",ca,ans);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: