题目地址:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemId=1313
这题的理论就是当且仅当(a,m)=1 时 a*k+b (1<=k<=m) 遍历mod m的完系
一开始的感觉就是暴力 从n/2 开始减 ,直到互素为止,于是直接用java大整数写了:
import java.math.*; import java.util.*; import java.io.*; public class Main { public static void main(String[] args) throws Exception { Scanner cin=new Scanner(System.in); int size=cin.nextInt(); for(int l=0;l<size;l++) { BigInteger n=cin.nextBigInteger(); BigInteger k=n.divide(new BigInteger("2")); while(n.gcd(k).compareTo(BigInteger.ONE)!=0) { k=k.subtract(BigInteger.ONE); } System.out.println(k); if(l<size-1) System.out.println(); } } }
竟然ac了 ,为啥不会超时?
理论解释是,当n=2*k+1 时 ,结果就是k, 当n=4*k时 结果就是2*k-1, 当n=4*k+2 时,结果就是2*k-2, 所以答案都离n/2距离很近,当然就不会超时了。
有了理论的分析 ,用c++也比较简单
但是还是java代码比较简洁~
#include<iostream> #include<cstring> using namespace std; void jminus(int a [],int n,int b) { a[n-1]-=b; for(int i=n-1;i>0;i--) { if(a[i]<0) { a[i]+=10; a[i-1]-=1; } } } void divide(int a [],int n ) { for(int i=0;i<n-1;i++) { if(a[i]%2==0) a[i]=a[i]/2; else { a[i]=a[i]/2; a[i+1]+=10; } } a[n-1]/=2; } int main() { int size=0; cin>>size; for(int l=0;l<size;l++) { char p[2010]; cin>>p; int n=strlen(p); int a[n]; for(int i=0;i<n;i++) a[i]=p[i]-'0'; if(a[n-1]%2==1) { divide(a,n); int start=0; while(a[start]==0) start++; for(int i=start;i<n;i++) cout<<a[i]; cout<<endl; } else { if(n==1) { int temp=a[0]; if(temp%4==2) { divide(a,n); jminus(a,n,2); } else { divide(a,n); jminus(a,n,1); } } else { int temp=a[n-1]+10*a[n-2]; if(temp%4==2) { divide(a,n); jminus(a,n,2); } else { divide(a,n); jminus(a,n,1); } } int start=0; while(a[start]==0) start++; for(int i=start;i<n;i++) cout<<a[i]; cout<<endl; } if(l<size-1) cout<<endl; } }