题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5391
题目大意:一个球初始体积为1,一天天变大,第一天变大1倍,第二天变大2倍,第n天变大n倍。问当第 n-1天的时候,体积变为多少。注意答案对n取模。
思路:题目意思搞了好久,其实就是第一天是1,第二天是1*2,第三天是1*2*3,也就是当第n天的时候是n!。那么答案就是(n-1)! % n。
题目里面n是10^9,不可能直接弄阶乘。这时可以想想,能不能找找规律看。
打表以后发现,如果是素数,答案就是n-1,否则就是0。当然这里4是个例外。
于是问题就转化成为求n是否为素数。求素数那么再简单不过了。最朴素的方法:对于一个素数n,看他的2~sqrt(n)范围里面,能不能被他整除。
注意这个程序,我刚开始用__int64定义变量,结果是TLE。因为碰到过这种情况,报着试一试的心态改为int,就AC了,跑了900多ms。
#include
#include
#include
#define LL __int64
int main()
{
int T;
int i,j,n,k;
scanf("%d",&T);
int flag=0;
while(T--)
{
flag=0;
scanf("%d",&n);
k=sqrt(n);
for(i=2;i<=k;i++)
{
if(n%i==0){
flag=1;break;
}
}
if(n==4){
printf("2\n");continue;
}
if(flag)printf("0\n");
else printf("%d\n",n-1);
}
return 0;
}
其实刚开始的时候,一直想着筛出素数来做。后来就用线性素数筛法写了一次。但是效果不好,也要800ms。
#include
#include
#include
#define Max 40005
int prime[40005];
bool isprime[40005];
int tot=0;
void sushu() //线性素数筛法
{
memset(isprime,true,sizeof(isprime));
memset(prime,0,sizeof(prime));
isprime[0]=false;
isprime[1]=false;
for(int i=2;i<=Max;i++)
{
if(isprime[i]){
prime[tot++]=i;
}
for(int j=i;j<=tot&&i*prime[j]<=Max;j++)
{
isprime[i*prime[j]]=false;
if(!(i%prime[j]))break;
}
}
}
int main()
{
sushu();
int T,n,k,i,j,flag;
scanf("%d",&T);
while(T--)
{
flag=0;
scanf("%d",&n);
if(n==4){
printf("2\n");continue;
}
k=sqrt(n);
for(i=0;prime[i]<=k;i++) //还是利用最朴素的判断一个数是否为素数的方法,但是有优化:在2-k里面,只要被其中的素数整除,就认为他不是素数了。这里就 //通过预处理出来的素数,把中间的合数筛去了。
{
if(n%prime[i]==0){
flag=1;break;
}
}
if(flag==0)printf("%d\n",n-1);
else printf("0\n");
}
return 0;
}
其实呢,在想着用处理素数的方法判断素数的时候,以为会有很大的效果,但是却不是这样,真的是很失望。后来我找到了别人的一份200 ms的代码。思路基本一致,就是素数筛的方法有点差异。那就膜拜一下。
#include
#include
#include
using namespace std;
#define mod 258280327
#define ll long long
int prime[100000]={2};
int cnt;
bool is_prime(int k){
for(int i=0;prime[i]*prime[i]<=k;i++){
if(k%prime[i]==0)return false;
}
return true;
}
int main(){
int t,n;
cnt=1;
for(int i=3;i<100000;i++){
if(is_prime(i)){
prime[cnt++]=i;
}
}
for(int i=1;i<=100;i++)
printf("%d ",prime[i]);
//for(int i=0;i<30;i++)cout<