Transcript 习题选讲_数论
习题选讲 赵浩泉 [email protected] 数论 1500 Prime Gap 1259 Sum of Consecutive Primes 1231 The Embarrassed Cryptography 1240 Faulty Odometer 1214 信号分析 1203 The Cubic End 1099 Packing Passengers 1014 Specialized Four-Dig 1119 Factstone Benchmark 2 2011-11-23 1500 Prime Gap 题目大意: 给出一个正整数k,计算出两个相邻的素 数,使得k在这两个素数之间,求出两个素 数之差。如果不存在这两个素数则输出0。 3 2011-11-23 1500 Prime Gap 解题思路: 题目等价于求出小于等于k的最大素数与大 于等于k的最小素数,并求出它们的差。 从k分别向下和向上枚举每个整数,判断是 否为素数,直到找到这两个素数。 4 2011-11-23 1500 Prime Gap bool isprime(int n) { if (n!=2&&n%2==0) return false; for (int i=3;i*i<=n;i+=2) if (n%i==0) return false; return true; } for (i=k;!isprime(i);i--); for (j=k;!isprime(j);j++); 5 2011-11-23 1259 Sum of Consecutive Primes 题目大意: 给出一个正整数,求出它有多少种方法可 以表示成连续的素数的和。 例如53 = 5 + 7 + 11 + 13 + 17 = 53,共有 两种方法。 数据范围为[2, 10000] 6 2011-11-23 1259 Sum of Consecutive Primes 解题思路: 先求出10000以内的所有素数。 对每个输入,枚举连续的素数的起点,寻 找是否有一段连续的素数与它相等,如果 有则累加答案。 7 2011-11-23 1259 Sum of Consecutive Primes p[0]=2;np=1; for (i=3;i<10000;i+=2) { isprime=true; for (j=0;j<np;j++) { if (p[j]>100) break; if (i%p[j]==0) isprime=false; } if (isprime) {p[n]=i;np++;} } 8 2011-11-23 1259 Sum of Consecutive Primes int cal(int n) { int ans=0; for (int i=0;i<np;i++) { int j=i,s=0; while (s<n&&j<np) {s+=p[j];j++;} if (s==n) ans++; } return ans; } 9 2011-11-23 1231 The Embarrassed Cryptography 题目大意: 给出两个正整数K和L,问K是否存在小于L 的质因数,有的话则找出最小的质因数。 4 <= K <= 10100 , 2 <= L <= 106 10 2011-11-23 1231 The Embarrassed Cryptography 解题思路: 先预处理不超过106 的所有素数。(筛法) 对每个不超过L的素数,检查是否能整除 K。 高精度除法。(压缩) 11 2011-11-23 1231 The Embarrassed Cryptography memset(prime,true,sizeof(prime)); p[0]=2; np=1; //prime number counter for (i=3;i<maxn;i+=2) { if (prime[i]==true) { p[np]=i; np++; for (j=i+i;j<maxn;j+=i) prime[i]=false; } } 12 2011-11-23 1231 The Embarrassed Cryptography m=strlen(s); if (m%9==0) k=0; else k=9-m%9; for (i=m;i>=0;i--) s[i+k]=s[i]; for (i=0;i<k;i++) s[i]='0'; m=strlen(s)/9; for (i=0;i<m;i++) { x[i]=0; for (j=0;j<9;j++) x[i]=x[i]*10+s[i*9+j]-'0'; } 13 2011-11-23 1231 The Embarrassed Cryptography ans=-1; for (i=0;i<np&&p[i]<l;i++) { temp=0; for (j=0;j<m;j++) temp=((long long)temp * 1000000000+x[j]) % p[i]; if (temp==0) { ans=p[i]; break; } } 14 2011-11-23 1240 Faulty Odometer 题目大意: 有个损坏的里程表,不能显示数字4,会从 数字3直接跳到数字5。 给出里程表的读数,求出实际里程。 15 2011-11-23 1240 Faulty Odometer 解题思路: 里程表能显示的数字为”012356789”,总 共9个,等价于九进制。以九进制的方式计 算实际里程。 16 2011-11-23 1240 Faulty Odometer int cal(int n) { int s=0,k=1,m=n; while (n>0) { int x=n%10; n/=10; if (x>4) x--; s+=x*k; k*=9; } return s; } 17 2011-11-23 1214 信号分析 题目大意: 数列a1=1, a3=3 a2n = an a4n+1 = 2*a2n+1 – an a4n+3 = 3*a2n+1 - 2*an 给出L,求1<=i<=L中aL=L的个数 18 2011-11-23 1214 信号分析 解题思路: 找规律。按二进制找。 a(1)=1 a(10)=1 a(11)=11 a(100)=1 a(101)=101 a(110)=11 a(111)=1111 猜想规律:数列的第n项为n的二进制串的 倒置。 19 2011-11-23 1214 信号分析 证明:用数学归纳法证明 当n=1和3时,a(1)=1,a(11)=11满足。 设n=xyz,则a(xyz0)=a(xyz)=zyx=0zyx,满足; a(xyz01)=2*a(xyz1)-a(xyz)=1zyx0-zyx =10zyx,满足; a(xyz11)=3*a(xyz1)-2*a(xyz)=1zyx0+1zyx-zyx0 =11zyx,满足。 因此得到证明。 20 2011-11-23 1214 信号分析 问题转换成求1<=i<=L的二进制里有多少个 是回文串。 枚举构成回文串的其中一半数字,从而构 造得到回文串,再与L比较大小。 L最多为32位,因此枚举的二进制串最多为 16位。 21 2011-11-23 1214 信号分析 void dfs(unsigned n,unsigned lev) { if (lev==0) { cal(n); return; } dfs(n<<1,lev-1); dfs((n<<1)+1,lev-1); return; } ans=0; dfs(0,16); 22 2011-11-23 1214 信号分析 void cal(unsigned n) { if (n==0) return; unsigned temp=n,l=0; while (temp>0) { temp>>=1; l++; } temp=(n<<l)|reverse(n); if (temp<=L) ans++; temp=(n<<(l-1))|reverse(n>>1); if (temp<=L) ans++; return; } 23 2011-11-23 1214 信号分析 unsigned reverse(unsigned n) { unsigned ret=0; while (n>0) { ret=(ret<<1)|(n&1); n>>=1; } return ret; } 24 2011-11-23 1203 The Cubic End 题目大意: 如果一个数字串,以1,3,7,9结尾,则 会有一个数,它的三次方以这个数字串结 尾,且长度不会超过这个数字串。现在给 出这个数字串,求出这个数。 25 2011-11-23 1203 The Cubic End 解题思路: 从低位向高位枚举,尝试用每个数字填入 这个位置,检查所得到的尾数是否相符, 相符则下一个位,直至枚举完所有位置。 检查尾数用三重循环(三次方),保存进 位。 26 2011-11-23 1203 The Cubic End scanf("%s",s); k=strlen(s); for (i=0;i<k;i++) n[i]=s[k-i-1]-48; z=0; for (i=0;i<k;i++){ for (m[i]=0;m[i]<=9;m[i]++){ temp=z; for (a=0;a<=i;a++) for (b=0;a+b<=i;b++){ c=i-a-b; temp=temp+m[a]*m[b]*m[c]; } if (temp%10==n[i]) break; } z=temp/10; } for (i=k-1;i>=0;i--) if (m[i]!=0) break; for (;i>=0;i--) printf("%d",m[i]); 27 2011-11-23 1099 Packing Passengers 题目大意: 有两种飞机A和B,花费分别为costA和 costB,容量分别为passengersA和 passengersB。现在要N个乘客,每个飞 机都要完全装满乘客才能起飞,问最小费 用。 28 2011-11-23 1099 Packing Passengers 解题思路: 当A,B其中一个容量为0时特判。 求出两种飞机的性价比,使得性价比低的 飞机尽量少。 从多到少枚举性价比高的飞机的数量,如 果剩余的乘客都能被另一种飞机装满,则 存在解。 29 2011-11-23 1099 Packing Passengers bool sol(long long ai,long long bi,long long &a,long long &b,long long n) { a=n/ai; while ((n-a*ai)%bi!=0) { if (a>0) a--; else return false; } b=(n-a*ai)/bi; return true; } if ((double)ax/ai<=(double)bx/bi) c=sol(ai,bi,a,b,n); else c=sol(bi,ai,b,a,n); 30 2011-11-23 1014 Specialized Four-Dig 题目大意: 求出所有在十进制,十二进制,十六进制 下各位数字之和相等的四位十进制数。 31 2011-11-23 1014 Specialized Four-Dig 解题思路: 枚举所有四位数,求出十进制,十二进 制,十六进制下各位数字之和,再判断是 否相等。 32 2011-11-23 1014 Specialized Four-Dig int sum(int i,int base) { int s=0; while (i>0) { s+=i%base; i/=base; } return s; } bool check(int i) { return sum(i,10)==sum(i,12)&&sum(i,10)==sum(i,16); } 33 2011-11-23 1119 Factstone Benchmark 题目大意: 1960年发行了4位计算机,从此以后每过10 年,计算机的位数变成两倍。输入某一个 年份,求出在这个年份的最大的整数n使得 n!能被该年份计算机的一个字表示。 34 2011-11-23 1119 Factstone Benchmark 解题思路: 先求出年份对应的字长。例如1981年16 位。 用科学记数法表示阶乘,以2为底,从指数 可以得到位数,与字长比较即可。 35 2011-11-23 1119 Factstone Benchmark x=k=1; m=(1<<(n/10-194)); for (i=1;k<=m;i++){ x*=i; while (x>=2){ x/=2; k++; } if (k<=m) ans=i; } 36 2011-11-23 谢谢! 37 2011-11-23