前文
不得不说,这次考试真的只是运气好而已~~
自己对某些初等数论的知识还不够熟悉,也不能灵活掌握(反正肯定没有yb那位AK的好)
所以又跑过来写总结.....
更重要的是,我们的Z老师也一定会在周一让我们写总结的!~~~
整体总结:
其实考的并不是太难,每道题多思考一下就可以做出来了
尴尬的是,我在考前就只做好了AC两道题的准备,结果做完后就在不停检查,后面两道就没怎么想了
经验1:任何时候一定要谦虚!!
把自己的姿态放低,排在最后一位,这样就有无限上升的空间了。但是也不要太自卑了~~~
经验2:一定不要懈怠!!
不管是文化课还是信息学,自己都有这个缺点,容易取得成绩后懈怠,这样就不能一直稳定下去,而自己做事情的时候也要学会坚持(特别是做题,要独立思考),既然自己已经取得了优势,就想办法把它扩大,而不是拿这点东西去浪~~
经验3:一定掌握每个知识点!!
自己现在有这么好的学习资源,也有azui大佬可以帮助我,如果自己还不能学好,就是自己的问题,也就是——知识点没有吃透!!
从这次考试也可看得出来T2,绞尽脑汁就是个公式板题,可见还是要把azui的课件继续嚼啊
经验4:学会总结归纳知识点
这一点不用多说,是用自己的失败一步步铺出来的,当然,文化课同样适用
切记!!我在新学期定下的目标还没有完成,一定要重新振作起来
————————————————————————————————————————————————————————
其实上面的都是给自己看的(如果觉得烦可以自动过滤)
题解:
总共4道题
T1:
题目描述
给定n,m,k都是小于10001的正整数,输出给定的n个数中,其m次幂能被k整除的数的个数。
输出满足条件的数的个数。
输入
两行组成,第一行是n,m,k。
第二行是n个正整数,不超过10001.
输出
输出满足条件的数的个数。
样例输入
3 2 50
9 10 11
样例输出
1
这道题就不说了,就是先来热脑的,直接用快速幂搜就行了,代码就不给了
T2:
题目描述
经过精灵族全力抵挡,精灵终于坚持到了联络系统的重建,于是精灵向人类求助,
大魔法师伊扎洛决定弓}用博士的最新科技来抗敌。
伊扎洛:“博士,还没好吗?”
博士:“只差一步了!只需要在正确的位置装上弹药就可以了!”
博士的最新科技是全新的炸弹,但是现在还需要一步装弹药的操作。博士的炸弹有
N!个位置可以装弹药(>.<),但是只有在正确的位置装上弹药才能启动,博士将
装弹药的位置编号为1到N!,一个位置i需要装弹药,当且仅当gcd(i, N!) ≠ 1且
N! mod i ≠ 0,现在博士不要求你求出所有装弹药位置,只需要你求出满足要求
的位置的数量就可以了。
输入
一个数N
输出
表示满足要求的位置数量,答案对mod1000000007输出
样例输入
4
样例输出
9
提示
【数据范围】
N <= 1000000
这就是我说的板子题,再加上一点小小的容斥思想,具体公式为:
其中suma表示n!以内的与n互质的数,sumb表示n!的约数个数,由于1被减了两次,要加上一次
其实就是:既然求不满足,就把总的减去满足的就是解
suma就是欧拉函数,sumb可以直接用公式求
至于怎么求p数组与w数组,用勒让德定理即可(有道以前的有道题用过)
推荐求n的欧拉函数用第二个,不用涉及到除法
记得取模
代码:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <cstdlib>
using namespace std;
#define ll long long
const int mod = 1e9 + 7;
const int MAXN = 1000003;
int n;
ll prime[MAXN] , pn , phi[MAXN];
bool vis[MAXN];
ll psum[MAXN];
void pr(){
for( int i =2 ; i <= n ; i ++ ){
if( vis[i] == 0 ){
phi[i] = i - 1;
prime[++pn] = i;
}
for( int j =1 ; j <= pn && 1ll * i * prime[j] <= n ; j ++ ){
vis[i*prime[j]] = 1;
if( i % prime[j] == 0 ){
phi[i*prime[j]] = phi[i] * prime[j];
break;
}
phi[i*prime[j]] = phi[i] * ( prime[j] - 1 );
}
}
}
ll qpow( ll x , ll y , ll mod ){
ll sum = 1;
while( y ){
if( y % 2 ) sum = sum * x % mod;
x = x * x % mod;
y /= 2;
}
return sum;
}
int main(){
scanf( "%d" , &n );
pr();
for( int i = 1 ; i <= pn ; i ++ ){
ll k = 1;
for( int j = 1 ; k * prime[i] <= n ; j ++ ){
k = k * prime[i];
psum[i] += n / k;
}
}
ll sum = 1;
for( int i = 2 ; i <= n ; i ++ ){
sum = sum * i % mod;
}
ll ans = 1 , ans2 = 1;
for( int i = 1 ; i <= pn ; i ++ ){
ans = ans * ( qpow( prime[i] , psum[i] - 1 , mod ) * ( prime[i] - 1 ) % mod ) % mod;
ans2 = ans2 * ( psum[i] + 1 ) % mod;
}
sum = sum - ans - ans2 + 1;
while( sum < 0 ){
sum += mod;
}
printf( "%lld" , sum );
return 0;
}
T3:
有一个数列,满足两个性质:
- 数列中任意两端相邻且长度相等的部分不完全相同,比如3 6 3 6 是不合法的。
- 该数列是左右满足条件1的数列中字典序最小的。给出一个整数N,求数列的第N项。
输入
一个整数N
N<=101000
输出
一个数,表示数列的第N项。
样例输入
20
样例输出
3
看起来很难,其实还是有点难度的(也是四道题中有难度的题目)
下面是来自llsw的题解:
由于要求数列不对称,所以我们可以先构造对称的,再让它变得不对称。
1-> 1, 2 ( 1, 1 + 1 ) -> 1, 2, 1, 3 ( 1, 2, 1, 2 + 1 ) -> 1, 2, 1, 3, 1, 2, 1, 4 ( 1, 2, 1, 3, 1, 2, 1, 3 + 1 ) -> ...
设数列为{an},则有:
n % 2 = 1 => an = 1
n % 4 = 2 => an = 2
n % 8 = 4 => an = 3
n % 16 = 8 => an = 4
...
n % ( 2 ^ x ) = 2 ^ ( x - 1 ) => an = x
n % ( 2 ^ x ) = 2 ^ ( x - 1 ) <=> n ≡2 ^ ( x - 1 ) ( mod 2 ^ x ) <=> ( n / ( 2 ^ ( x - 1 ) ) ) ≡1 ( mod 2 )
所以我们只需要持续取模、除法直到出现n' ≡1 ( mod 2 )的情况即可
代码
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <cstdlib>
using namespace std;
int a[1003] , len , ans;
char s[1003];
int sum[1003] , lena;
int main(){
scanf( "%s" , s );
len = strlen( s );
for( int i = 0 ; i < len ; i ++ )
a[i+1] = s[i] - '0';
while( 1 + 1 == 2 ){
ans ++;
if( a[len] % 2 == 1 ){
printf( "%d" , ans );
return 0;
}
int x = 0;
for( int i = 1 ; i <= len ; i ++ ){
a[i] = ( a[i] + x * 10 );
x = a[i] % 2;
a[i] /= 2;
}
}
return 0;
}
T4:
题目描述
给定整数N,求1<=x,y<=N且Gcd(x,y)为素数的数对(x,y)有多少对?
输入
一个整数
1<=N<=1000000
输出
一个整数
样例输入
4
样例输出
4
提示
【样例解释】
(2,2),(2,4),(3,3),(4,2)
其实是做过的,我们知道,欧拉函数就是找在n以内与n互质的数,那么我们这样思考,设有一个数是x是在y范围以内与y互质的,就一定满足:
gcd(y , x) = 1
那么,如果我们同时将n乘上一个素数,如3,则就一定有:
gcd( 3*y , 3*x ) = 3
那么只要保证y*3不大于n,那么y及其y以内的数都可以满足咯,所以最后的答案就是:
其中pn为n以内质数个数,prime存的是质数。
为什么要乘2呢,因为反过来也是一种情况
为什么要加1呢?是因为我们要加上(prime[i],prime[i])这一种情况,但是其它x==y相同的不能算
可以用前缀和
代码:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
using namespace std;
int n ;
#define ll long long
const int MAXN = 1e7 + 3;
int prime[MAXN] , pn;
ll phi[MAXN];
bool vis[MAXN];
void pr(){
for( int i = 2 ; i <= n ; i ++ ){
if( !vis[i] ){
prime[++pn] = i;
phi[i] = i - 1;
}
for( int j = 1 ; j <= pn && 1ll * i * prime[j] <= n ; j ++ ){
vis[i*prime[j]] = 1;
if( i % prime[j] == 0 ){
phi[i*prime[j]] = phi[i] * prime[j];
break;
}
phi[i*prime[j]] = phi[i] * ( prime[j] - 1 );
}
}
for( int i = 2 ; i <= n ; i ++ )
phi[i] = phi[i] + phi[i-1];
}
int main(){
scanf( "%d" , &n );
pr();
ll ans = 0;
for( int i = 1; i <= pn ; i ++ ){
ans = ans + phi[n/prime[i]] * 2 + 1;
}
printf( "%lld" , ans );
return 0;
}