A
Solution
1.扩展欧几里得算法板子题。
题目提取式子: ( x + k m ) % L = ( y + k n ) % L (x+km)\%L=(y+kn)\%L (x+km)%L=(y+kn)%L
优化: x + k m = y + k n − v L x+km = y+kn - vL x+km=y+kn−vL
k ( m − n ) + L v = y − x k(m-n) + Lv = y-x k(m−n)+Lv=y−x
与 a x + b y = g c d ( a , b ) ax+by=gcd(a, b) ax+by=gcd(a,b)式子雷同,
求出x与y的一组解,如果y-x为a、b最大公因数的倍数则有解,否则无解。
Code
/*************************************
* @problem: problem title.
* @author: iamshroud.
* @time: 2021-??-??.
*************************************/
#include <algorithm>
#include <cmath>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <ctime>
#include <iomanip>
#include <iostream>
#include <list>
#include <map>
#include <queue>
#include <set>
#include <stack>
#include <string>
#include <vector>
// #include <unordered_map>
typedef long long ll;
#define itn int //ovo
#define MOD 1000000007
#define intmax 2147483647
#define memmax 0x7fffffff
using namespace std;
inline ll read()
{
ll x=0,f=1;char ch=getchar();
while (ch<'0'||ch>'9'){
if (ch=='-') f=-1;ch=getchar();}
while (ch>='0'&&ch<='9'){
x=x*10+ch-48;ch=getchar();}
return x*f;
}
ll m, n, L;
ll a, b, x, y, c;
ll exgcd(ll a, ll b, ll& x, ll& y)
{
if(!b)
{
x = 1;
y = 0;
return a;
}
ll d = exgcd(b, a%b, x, y);
ll x2 = x;
x = y;
y = x2-a/b*y;
return d;
}
void solve()
{
ll x1, y1;
cin >> x1 >> y1 >> m >> n >> L;
a = m - n;
b = L;
c = y1-x1;
if(a < 0)
{
a = -a;
c = -c;
}
ll gg = exgcd(a, b, x, y);
// c 为 gcd(a, b)的倍数,有解
if(c%gg == 0)
{
// x = x*c/gg;
L = L/gg;
// 乘以倍数,使得答案对称
x = (x*c/gg%L+L)%L;
cout << x;
return ;
}
cout << "Impossible";
}
int main(void)
{
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
// come on
solve();
return 0;
}
B
Solution
1.n的数据过大,用埃氏筛会超时,此处采用欧拉筛
2.对于查找答案,可以使用滑动窗口的思想。
由于前缀素数和具有单调递增的性质,对于寻找区间,left值可以先遍历到大于n的地方,再寻找对应的right。
Code
/*************************************
* @problem: problem title.
* @author: iamshroud.
* @time: 2021-??-??.
*************************************/
#include <algorithm>
#include <cmath>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <ctime>
#include <iomanip>
#include <iostream>
#include <list>
#include <map>
#include <queue>
#include <set>
#include <stack>
#include <string>
#include <vector>
// #include <unordered_map>
typedef long long ll;
#define itn int //ovo
#define MOD 1000000007
#define intmax 2147483647
#define memmax 0x7fffffff
using namespace std;
int t;
int n;
bool vis[40000005];
int prime[40000005];
int cnt;
int pre[40000005];
void prework()
{
for(int i=2; i<=40000000; i++)
{
if(!vis[i])
{
prime[++cnt] = i;
}
for(int j=1; j<=cnt && i*prime[j] <=40000000; j++)
{
vis[i*prime[j]] = true;
if(i % prime[j] == 0)
break;
}
}
for(int i=1; i<=cnt; i++)
{
pre[i] = pre[i-1] + prime[i];
}
}
void solve()
{
ll ans = 0;
for(int i=1, j=1; prime[i]<=n && j<=cnt; i++)
{
// 枚举j
while(j<=cnt && pre[j]-pre[i-1] < n)
j++;
if(pre[j]-pre[i-1] == n)
ans++;
}
// cout << "ans = ";
cout << ans << endl;
}
int main(void)
{
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
prework();
// cout << "cnt = " << cnt << endl;
cin >> t;
// come on
while(t--)
{
cin >> n;
solve();
}
return 0;
}
C
Solution
1.区间筛模板题
Code
/*************************************
* @problem: problem title.
* @author: iamshroud.
* @time: 2021-??-??.
*************************************/
#include <algorithm>
#include <cmath>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <ctime>
#include <iomanip>
#include <iostream>
#include <list>
#include <map>
#include <queue>
#include <set>
#include <stack>
#include <string>
#include <vector>
// #include <unordered_map>
typedef long long ll;
#define itn int //ovo
#define MOD 1000000007
#define intmax 2147483647
#define memmax 0x7fffffff
using namespace std;
inline ll read()
{
ll x=0,f=1;char ch=getchar();
while (ch<'0'||ch>'9'){
if (ch=='-') f=-1;ch=getchar();}
while (ch>='0'&&ch<='9'){
x=x*10+ch-48;ch=getchar();}
return x*f;
}
ll n;
ll l, r;
bool is_prime_small[1000005];//用于线性筛[0, sqrt(b)]的
bool is_prime[1000005];// 真正的素数(偏移量为a)
ll prime[1000005];// 存储素数
ll cnt;
//区间筛
// [a, b] -> [0, b-a]
void segment_sieve(ll a, ll b)
{
cnt = 0;
// 假设全为素数,遍历到sqrt(b)即可
for(ll i=2; i*i<=b; i++)
{
is_prime_small[i] = true;
}
// [a, b] 区间全部默认是素数
for(ll i=0; i<=b-a; i++)
{
is_prime[i] = true;
}
// 特判1
if(a==1)
is_prime[1-a] = false;
for(ll i=2; i*i<=b; i++)
{
if(is_prime_small[i])
{
// 线性筛思想
for(ll j=2*i; j*j<=b; j+=i)
{
is_prime_small[j] = false;
}
// max(2ll, (i+a-1)/i) * i
// 求距离a最近,但比a大的数
for(ll j=max(2ll, (i+a-1)/i)*i; j<=b; j+=i)
{
// j isn't a prime
is_prime[j-a] = false;
}
}
}
// 记录答案
for(ll i=0; i<=b-a; i++)
{
// a+i is prime
if(is_prime[i])
prime[++cnt] = a+i;
}
}
void solve()
{
segment_sieve(l, r);
// for(int i=1; i<=cnt; i++)
// {
// cout << "prime[" << i << "] = " << prime[i] << endl;
// }
if(cnt < 2)
{
printf("There are no adjacent primes.\n");
return ;
}
ll mindis = intmax, maxdis = -1;
ll minleft = 0, minright = 0;
ll maxleft = 0, maxright = 0;
for(int i=2; i<=cnt; i++)
{
ll dis = prime[i]-prime[i-1];
if(dis < mindis)
{
mindis = dis;
minleft = prime[i-1], minright = prime[i];
}
if(dis > maxdis)
{
maxdis = dis;
maxleft = prime[i-1], maxright = prime[i];
}
}
printf("%lld,%lld are closest, %lld,%lld are most distant.\n", minleft, minright, maxleft, maxright);
}
int main(void)
{
// come on
ll t;
cin >> t;
while(t--)
{
cin >> l >> r;
solve();
}
// while(scanf("%lld%lld", &l, &r) == 2)
// solve();
return 0;
}
D
Solution
1.先线性筛选出质数
2.高到低遍历质数,能除n就除n
Code
/*************************************
* @problem: cf_init.cpp.
* @author: iamshroud.
* @time: 2021-11-02. 周二
*************************************/
#include <iostream>
#include <cstdio>
#include <cmath>
#include <cstdlib>
#include <ctime>
#include <string>
#include <cstring>
#include <algorithm>
#include <vector>
#include <stack>
#include <queue>
#include <map>
#include <set>
#include <iomanip>
#include <list>
using namespace std;
typedef long long ll;
#define MOD 1000000007
#define intmax 2147483647
#define memmax 0x7fffffff
ll quickPow(ll n,ll p,ll k=intmax)
{
ll ans = 1;
ll base = n;
while (p)
{
//最后一位为1
if(p&1)
{
ans *= base;
ans %= k;
}
//去掉一位数
base *= base;
base %= k;
p >>= 1;
}
return ans;
}
ll t;
ll k;
bool isprime[30005];
ll prime[30005];
ll cnt;
void predeal()
{
for(int i=2; i<=30000; i++)
{
isprime[i] = true;
}
for(int i=2; i*i<=30000; i++)
{
if(isprime[i])
{
for(int j=2*i; j<=30000; j+=i)
{
isprime[j] = false;
}
}
}
for(int i=2; i<=30000; i++)
{
if(isprime[i])
prime[++cnt] = i;
}
// for(int i=cnt; i>=cnt-20; i--)
// {
// cout << prime[i] << ' ';
// }
// cout << endl;
}
void solve()
{
// cout << "ans == ";
// init
ll n = 1;
cin >> k;
for(int i=1; i<=k;i++)
{
ll p, e;
cin >> p >> e;
n *= quickPow(p, e);
}
// cout << "n = " << n << endl;
n--;
for(int i=cnt; i>=1; i--)
{
if(prime[i] > n)
continue;
if(n == 1)
break;
ll num = 0;
while(n % prime[i] == 0)
{
num++;
n /= prime[i];
}
if(num)
cout << prime[i] << ' ' << num << " ";
}
// for(int i=cnt; i>=1; i--)
// {
// cout << arr[i].id << " " << arr[i].value << " ";
// }
cout << endl;
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
predeal();
cin >> t;
while (t--)
{
solve();
}
return 0;
}
E
Solution
1.原本是想欧拉筛加记录质因数,再统计相同的数字的个数再计算答案,但发现超时了,需要一些手段。
2.可以使用一个minprime[i]
数组来记录i
的最小质因数,这样在分解x的质因数时速度会快很多,最坏情况 O ( n ) − > O ( 1 ) O(n)->O(1) O(n)−>O(1)
3.将x分解成质因数形式后,简化排列组合计算。
显然,令 x = p 1 a 1 p 2 a 2 . . . . p k a k x=p_1^{a_1}p_2^{a_2}....p_k^{a_k} x=p1a1p2a2....pkak
则m的最大值为 ∑ i = 1 k a i \sum_{i=1}^k a_i ∑i=1kai
方案数,通过排列组合思想,为

C m a 1 C m − a 1 a 2 . . . C m − a 1 − . . . − a k − 1 a k C_{m}^{a_1}C_{m-a_1}^{a_2}...C_{m-a_1-...-a_{k-1}}^{a_k} Cma1Cm−a1a2...Cm−a1−...−ak−1ak
由 C m n = m ! n ! ( m − n ) ! C_m^n\ =\ \frac{m!}{n!(m-n)!} Cmn = n!(m−n)!m! 得
上述式子可化为
m ! a 1 ! ( m − a 1 ) ! ( m − a 1 ) ! a 2 ! ( m − a 1 − a 2 ) ! . . . ( m − a 1 − a 2 − . . . a k − 1 ) ! a k ! ( m − a 1 − a 2 − . . − a k ) ! \frac{m!}{a_1!(m-a_1)!}\frac{(m-a_1)!}{a_2!(m-a_1-a_2)!}...\frac{(m-a_1-a_2-...a_{k-1})!}{a_k!(m-a_1-a_2-..-a_k)!} a1!(m−a1)!m!a2!(m−a1−a2)!(m−a1)!...ak!(m−a1−a2−..−ak)!(m−a1−a2−...ak−1)!
由于 ( m − a 1 − a 2 − . . − a k ) ! = 1 (m-a_1-a_2-..-a_k)!\ =\ 1 (m−a1−a2−..−ak)! = 1
上述式子化简得
m ! a 1 ! a 2 ! . . . a k ! \frac{m!}{a_1!a_2!...a_k!} a1!a2!...ak!m!
由数据得,m最多不超过20,预处理好前20的阶乘即可。
Code
/*************************************
* @problem: cf_init.cpp.
* @author: iamshroud.
* @time: 2021-11-02. 周二
*************************************/
#include <iostream>
#include <cstdio>
#include <cmath>
#include <cstdlib>
#include <ctime>
#include <string>
#include <cstring>
#include <algorithm>
#include <vector>
#include <stack>
#include <queue>
#include <map>
#include <set>
#include <iomanip>
#include <list>
using namespace std;
typedef long long ll;
#define MOD 1000000007
#define intmax 2147483647
#define memmax 0x7fffffff
ll t;
ll x;
bool not_prime[1000005];
ll prime[100005];
ll minprime[1000005];//这个数的最小质因数
ll cnt;
ll pre[30];
void predeal()
{
const int maxn = 1000000;
for(int i=2; i<=maxn; i++)
{
if(!not_prime[i])
{
prime[++cnt] = i;
minprime[i] = i;
}
for(int j=1; j<=cnt && i*prime[j]<=maxn; j++)
{
not_prime[i*prime[j]] = true;
minprime[i*prime[j]] = prime[j];//记录最小质因数
if(i % prime[j] == 0)
break;
}
}
pre[0] = 1;
for(ll i=1; i<=25; i++)
pre[i] = pre[i-1]*i;
}
inline void solve()
{
scanf("%lld", &x);
// cout << "ans = ";
// spj
if(!not_prime[x])
{
printf("1 1\n");
return ;
}
ll m = 0;
vector<int>v;
while(x != 1)
{
ll tmp = 0;
while(x % minprime[x] == 0)
{
m++;
tmp++;
x /= minprime[x];
}
if(tmp)
v.push_back(tmp);
}
ll num = pre[m];
for(int i=0; i<v.size(); i++)
{
num /= pre[v[i]];
}
printf("%lld %lld\n", m, num);
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
predeal();
scanf("%lld", &t);
while (t--)
{
solve();
}
return 0;
}