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;
}
后来得知,因为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;
}
相关文章推荐
- Round B APAC Test 2017 Problem B. Sherlock and Watson Gym Secrets
- Problem A. Sherlock and Parentheses Google APAC 2017 University Test Round B
- Problem C. Watson and Intervals Google APAC 2017 University Test Round B
- Problem A. Diwali lightings Google APAC 2017 University Test Round E
- Problem A. Vote Google APAC 2017 University Test Round D
- Round B APAC Test 2017 Problem A. Sherlock and Parentheses
- Problem A. Monster Path Google APAC 2017 University Test Round C
- Problem A. Lazy Spelling Bee Google APAC 2017 University Test Practice Round
- Problem C. Codejamon Cipher Google APAC 2017 University Test Round D
- Problem B. Robot Rock Band Google APAC 2017 University Test Practice Round
- Problem B. Beautiful Numbers Google APAC 2017 University Test Round E
- Problem B. Safe Squares Google APAC 2017 University Test Round C
- Problem A. Country Leader Google APAC 2017 University Test Round A
- Problem C. Evaluation Google APAC 2017 University Test Round C
- Problem C. Partioning Number Google APAC 2017 University Test Round E
- Round B APAC Test 2017 Problem C. Watson and Intervals
- Round B APAC Test 2017 Problem D. Sherlock and Permutation Sorting
- Problem C. Jane's Flower Shop Google APAC 2017 University Test Round A
- Problem C. Not So Random Google APAC 2017 University Test Practice Round
- Problem A. Travel Google APAC 2016 University Test Round B