一.整数分解的唯一性与gcd,lcm
1.
P1072[NOIP2009 提高组] Hankson 的趣味题
题意:已知a,a1,b,b1 x与a的的最大公约数是a1,x与b的最大公倍数是b1
求解有多少满足的x
思路:
gcd(x,a)=a1,x=k1a1,a=k2a1,gcd(k1,k2)=1
反证:gcd(k1,k2)=k(k!=1),k1=kp,k2=kq ->x=kk1a1,a=kk2a1,gcd(x,y)=ka1
结论进一步可推得:对于两个正整数a,b,若gcd(a,b)=k,gcd(a/k,b/k)=1
lcm(x,b)=b1 => x*b/gcd(x,b)=b1 =>gcd(x,b)=x*b/b1 => gcd(b1/b,b1/x)=1
结论进一步可推得:对于两个正整数a,b,若lcm(a,b)=k,gcd(k/a,k/b)=1
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #define endl '\n'
- #define ios ios::sync_with_stdio(false), cin.tie(nullptr), cout.tie(nullptr)
- #define ms(x,y) memset(x,y,sizeof x);
- #define YES cout<<"YES"<<'\n';
- #define NO cout<<"NO"<<'\n';
- #define fr(i,z,n) for(int i = z;i <= n; i++)
- #define ufr(i,n,z) for(int i = n;i >= z; i--)
- typedef long long ll;
- const ll maxn = 2e5 + 10, inf = 1e18;
- const ll mod = 1e9 + 7;
- using namespace std;
- int gcd(int a, int b) { //辗转相除法求最大公约数
- return !b ? a : gcd(b, a % b);
- }
- void solve() {
- int a, a1, b, b1;
- cin >> a >> a1 >> b >> b1;
- int ans = 0;
- int x = b1;
- set<int>s;
- for (int i = 1; i * i <= x; i++) { //找出最大公倍数的因子
- if (x % i == 0) {
- s.insert(i);
- s.insert(x / i);
- }
- }
- for (auto y : s) { //枚举因子
- if (y % a1 == 0 && gcd(y / a1, a / a1) == 1 && gcd(b1 / y, b1 / b) == 1) {
- ans++;
- }
- }
- cout << ans << '\n';
- }
- signed main()
- {
- ios;
- int t=1;
- cin >> t;
- while (t--) {
- solve();
- }
- }
2.
cf1866/problem/B
给定两个数x,y的的质因数分解式Ai,Bi表示x的质数,指数;Ci,Di表示y的质数,指数
求有多少对p,q满足lcm(p,q)=x,gcd(p,q)=y
思路1.p*q=x*y 2.对于某个质数的指数,gcd相当于取min,lcm相当于取max
对于某个素数,
1.若Bi
3.Bi>Di,ans=ans*2
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #define endl '\n'
- #define ios ios::sync_with_stdio(false), cin.tie(nullptr), cout.tie(nullptr)
- #define ms(x,y) memset(x,y,sizeof x);
- #define YES cout<<"YES"<<'\n';
- #define NO cout<<"NO"<<'\n';
- #define fr(i,z,n) for(int i = z;i <= n; i++)
- #define ufr(i,n,z) for(int i = n;i >= z; i--)
- typedef long long ll;
- const int N = 2000005, mod = 998244353;
- using namespace std;
- int a[N];
- int b[N];
- int c[N];
- int d[N];
- int mp1[N];
- int mp[N];
- void solve() {
- int n;
- cin >> n;
- fr(i, 1, n) {
- cin >> a[i];
- }
- fr(i, 1, n) {
- cin >> b[i];
- mp1[a[i]] = b[i];
- }
- int m;
- cin >> m;
- fr(i, 1, m) {
- cin >> c[i];
- }
- fr(i, 1, m) {
- cin >> d[i];
- mp[c[i]] = d[i];
- }
- int ans = 1;
- for (int i = 1; i <= 2000000; ++i){
- if (mp1[i] < mp[i]) {
- cout << 0 << '\n';
- return;
- }
- else if (mp1[i] > mp[i]) {
- ans *= 2;
- ans %= mod;
- }
- }
- cout << ans%mod << '\n';
- }
- signed main()
- {
- ios;
- int t = 1;
- //cin >> t;
- while (t--) {
- solve();
- }
- }
3.
P1593 因子和
求a^b得因子和,对出它对 9901 取模的结果
a<=5e7,b<=5e7
思路:推导过程:整数的唯一分解定理,对a进行质因数分解
a=p1^k1 *p2^k2 *p3^k3 ...*pn^kn->对a^b进行质因数分解
a^b=p1^(k1*b) *p2^(k2*b)...*pn^(kn*b)
因子和求解 ans=(1+p1^1+p1^2...p1^(k1*b))*(1+p2^1+p2^2...p2^(k2*b)*...*(1+pn^1+pn^2...pn^(n*b)
等比数列求和qi^n-1/qi-1相乘
除法逆元
当qi-1与mod互质时,逆元为pow(qi-1,mod-2)
不互质时,(p-1)%mod==0,p%mod==1,->(1+pi^1+pi^2...pi^(k1*b))%mod->1+k1*b
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #define endl '\n'
- #define ios ios::sync_with_stdio(false), cin.tie(nullptr), cout.tie(nullptr)
- #define ms(x,y) memset(x,y,sizeof x);
- #define YES cout<<"YES"<<'\n';
- #define NO cout<<"NO"<<'\n';
- #define fr(i,z,n) for(int i = z;i <= n; i++)
- #define ufr(i,n,z) for(int i = n;i >= z; i--)
- #define int long long
- typedef long long ll;
- const ll maxn=2e5+10,inf = 1e18 ;
- const ll mod = 9901;
- using namespace std;
- int mp[10010][2];
-
- ll poww(ll x, ll k) {
- if (k == 1) return x;
- if (k == 0) return 1;
- ll tmp = poww(x, k / 2);
- if (k & 1) return tmp * tmp % mod * x % mod;
- return tmp * tmp % mod;
- }
-
- void solve() {
- int a, b;
- cin >> a >> b;
- if (a== 0) { //特判
- cout << 0 << '\n';
- return;
- }
- int cnt = 0;
- for (int i = 2; i * i <= a; i++) {
- if (a % i == 0) {
- mp[++cnt][0]=i;
- mp[cnt][1] = 1;
- a /= i;
- while (a % i == 0) {
- mp[cnt][1]++;
- a /= i;
- }
- }
- }
- if (a != 1) {
- mp[++cnt][0] = a;
- mp[cnt][1]++;
- }
- int ans = 1;
- fr(i, 1, cnt) {
- int x = mp[i][0];
- int y = mp[i][1];
- if (x%mod==1) {
- ans = ans%mod * ( y * b + 1) % mod;
- }
- else { //互质
- ans = ans%mod * (((poww(x, (y * b + 1) % mod)) - 1 + mod) % mod) * (poww((x - 1+mod)%mod, mod - 2) % mod);
- }
- }
- cout << (ans%mod+mod)%mod<< '\n';
- }
- signed main(){
- ios;
- int t=1;
- //cin >> t;
- while (t--) {
- solve();
- }
- }
4.
P1414 又是毕业季II
题意:老师给每位同学评了一个能力值。从n个学生中挑出k个人使得他们的默契程度(即能力值的最大公约数)最大
总共 n 行,第i 行为k=i情况下的最大默契程度。
n<=10^4,m<=10^6
k个数中最大公约数:k个数中共有的因子最大的
于是可以将所有数的因子找出并记录个数
因为因子值越小,个数越多,满足单调性,记录最大值,不断缩小直到个数大于等于k
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #define endl '\n'
- #define ios ios::sync_with_stdio(false), cin.tie(nullptr), cout.tie(nullptr)
- #define ms(x,y) memset(x,y,sizeof x);
- #define YES cout<<"YES"<<'\n';
- #define NO cout<<"NO"<<'\n';
- #define fr(i,z,n) for(int i = z;i <= n; i++)
- #define ufr(i,n,z) for(int i = n;i >= z; i--)
- typedef long long ll;
- const ll maxn = 2e5 + 10, inf = 1e18;
- const ll mod = 1e9 + 7;
- using namespace std;
- int a[maxn];
- void solve() {
- int n;
- cin >> n;
- map<int, int>mp;
- int Max = 0;
- fr(i, 1, n) {
- cin >> a[i];
- Max = max(Max, a[i]);
- for (int j = 1; j *j <= a[i]; j++) {
- if (a[i] % j == 0) {
- mp[j]++;
- if (j* j != a[i]) {
- mp[a[i]/j]++;
- }
- }
- }
- }
- fr(i, 1, n) {
- while (mp[Max] < i) Max--;
- cout << Max << '\n';
- }
- }
- signed main()
- {
- ios;
- int t = 1;
- //cin >> t;
- while (t--) {
- solve();
- }
- }
二。组合数恒等式 ->杨辉三角
P2822[NOIP2016 提高组] 组合数问题
题意:给定n,m,k,对于所有的0<=i<=n,0<=j<=min(i,m),有多少对C(j,i)%k==0
思路:
1.组合数公式 50分
2.组合恒等式 C(n,m)=C(n-1,m-1)+C(n-1,m)->杨辉三角(n相当于行,m相当于列,每个数等于上方两数之和)
杨辉三角的第n行的m个数可表示为 C(n-1,m-1),即为从n-1个不同元素中取m-1个元素的组合数。
预处理出杨辉三角,然后对每个数%k,二维前缀和,特殊的对于每行比上一行多出的进行处理
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #define endl '\n'
- #define ios ios::sync_with_stdio(false), cin.tie(nullptr), cout.tie(nullptr)
- #define ms(x,y) memset(x,y,sizeof x);
- #define YES cout<<"YES"<<'\n';
- #define NO cout<<"NO"<<'\n';
- #define fr(i,z,n) for(int i = z;i <= n; i++)
- #define ufr(i,n,z) for(int i = n;i >= z; i--)
- typedef long long ll;
- const ll maxn=2e5+10,inf = 1e18 ;
- const ll mod = 1e9 + 7;
- using namespace std;
- int a[maxn];
- int c[2005][2005];
- int s[2005][2005]; //记录矩阵前缀和
- int t, k;
- void init() {
- c[1][1] = 1;
- fr(i, 0, 2000) {
- c[i][0] = 1;
- }
- fr(i, 2, 2000) {
- fr(j, 1, i) {
- c[i][j] = (c[i - 1][j - 1] + c[i - 1][j])%k;
- }
- }
- //fr(i, 1, 10) {
- // fr(j, 0, i) {
- // cout << c[i][j] << ' ';
- // }
- // cout << '\n';
- //}
- fr(i, 1, 2000) {
- fr(j, 1, i) {
- s[i][j] = s[i][j] + s[i - 1][j] + s[i][j - 1] - s[i - 1][j - 1]; //二维前缀和
- if (c[i][j] == 0) s[i][j] += 1;
- }
- s[i][i] = s[i][i - 1];
- }
- /*fr(i, 1, 10) {
- fr(j, 1, i) {
- cout << s[i][j] << ' ';
- }
- cout << '\n';
- }*/
-
- }
- void solve(){
- cin >> t >> k;
- init();
- fr(i, 1, t) {
- int n, m;
- cin >> n >> m;
- if (m > n) m = n;
- cout << s[n][m] << '\n';
- }
- }
- signed main()
- {
- ios;
- int t=1;
- //cin >> t;
- while (t--) {
- solve();
- }
- }