目录
P1143 进制转换
P1100 高低位交换
P1866 编号
P3913 车的攻击
P3383 【模板】线性筛素数
P1029 [NOIP2001 普及组] 最大公约数和最小公倍数问题
P1572 计算分数
P4057 [Code+#1] 晨跑
P2651 添加括号III
P2660 zzc 种田
P1403 [AHOI2005] 约数研究
P1469 找筷子
P1246 编码
P2926 [USACO08DEC] Patting Heads S
P1835 素数密度
P1414 又是毕业季II
P1143 进制转换
inline void solve()
{
int n, m;
string s;
cin >> n >> s >> m;
int sum = 0, k = 0;
// 将n进制转换为10进制
for (int i = 0; i < s.size(); i++)
{
if (s[i] < 'A')
{
k = (s[i] - '0') * pow(n, s.size() - i - 1);
sum += k;
}
else
{
k = (s[i] - 'A' + 10) * pow(n, s.size() - i - 1);
sum += k;
}
}
// 将10进制转换为m进制
vector<int> A;
while (sum > 0)
{
A.pb(sum % m);
sum /= m;
}
for (int i = A.size() - 1; i >= 0; i--)
{
if (A[i] < 10)
cout << A[i];
else
printf("%c", A[i] - 10 + 'A'); // 注意要用%c
}
}
P1100 高低位交换
inline void solve()
{
unsigned int n; //范围是2^32,signed是2^31
cin >> n;
cout << (n >> 16) + (n << 16);
}
P1866 编号
const int mod = 1e9 + 7;
int a[51];
inline void solve()
{
int n;
LL s = 1;
cin >> n;
ff(i, n) cin >> a[i];
sort(a + 1, a + n + 1);
ff(i, n)
{
s *= (a[i] - i + 1);
s %= mod;
}
cout << s;
}
P3913 车的攻击
第一点:在unique之前必须保证去重数组有序,也就是得sort一下。
第二点:unique并不会生成一个新的数组,而是将原数组多余的部分“移”到了数组之后,同时unique本身还会返回一个指针,指向去重之后的最后一位。利用c++可以指针相加减的特点,我们可以通过 unique-数组指针 来知道去重之后数组的“大小”
const int N = 1e6 + 10;
LL a[N], b[N];
LL n, k;
inline void solve()
{
scanf("%lld%lld", &n, &k);
f(i, k) scanf("%lld%lld", &a[i], &b[i]);
// cin >> a[i] >> b[i];
sort(a, a + k);
sort(b, b + k);
LL x = unique(a, a + k) - a;
LL y = unique(b, b + k) - b;
printf("%lld", n * n - (n - x) * (n - y));
}
P3383 【模板】线性筛素数
const int N = 1e8 + 10;
int primes[N], cnt;
bool st[N];
void get_primes(int n)
{
for (int i = 2; i <= n; i++)
{
if (!st[i])
{
primes[++cnt] = i; // i如果是质数,就加到数组中
}
for (int j = 1; primes[j] <= n / i; j++) // 从小到大枚举所有质数
{
st[primes[j] * i] = true; // 把当前的质数和i的乘积筛掉
if (i % primes[j] == 0)
break; // 成立时,primes[j]一定是i的最小质因子,primes[j]也一定是primes[j]*i的最小质因子;不成立时,primes[j]一定小于i的所有质因子,primes[j]也一定是primes[j]*i的最小质因子
}
}
}
inline void solve()
{
int n, m;
cin >> n >> m;
get_primes(n);
while (m--)
{
int x;
cin >> x;
cout << primes[x] << endl;
}
}
P1029 [NOIP2001 普及组] 最大公约数和最小公倍数问题
两个数的积等于它们最大公约数和它们最小公倍数的积。公式表示为 a×b=gcd(a,b)×lcm(a,b)
const int N = 1e6 + 10;
LL m, n, ans;
inline void solve()
{
cin >> m >> n;
if (m == n)
ans--;
n *= m;
for (LL i = 1; i <= sqrt(n); i++)
{
if (n % i == 0 && __gcd(i, n / i) == m)
ans += 2;
}
cout << ans;
}
P1572 计算分数
int a, b, c, d;
int ans1, ans2;
inline void solve()
{
scanf("%d/%d", &a, &b);
while ((scanf("%d/%d", &c, &d)) != EOF)
{
int gcd = __gcd(b, d);
int lcm = b * d / gcd;
ans2 = lcm;
ans1 = a * (lcm / b) + c * (lcm / d);
a = ans1 / (__gcd(ans1, ans2));
b = ans2 / (__gcd(ans1, ans2));
}
ans1 = a;
ans2 = b;
if (ans2 < 0)
{
ans1 =- ans1;
ans2 =- ans2;
}
if (ans2 == 1)
printf("%d\n", ans1);
else
printf("%d/%d\n", ans1, ans2);
}
P4057 [Code+#1] 晨跑
inline void solve()
{
LL a, b, c;
cin >> a >> b >> c;
cout << a * b * c / __gcd(b, c) / __gcd(a, b * c / __gcd(b, c));
}
P2651 添加括号III
a1肯定是分子,a2肯定是分母
a1/(a2/a3/a4/...)=a1a3a4.../a2,所以我们只要确认a1a3a4.../a2是否是整数。
如果进行约分,知道a2能被约分成1,那么就是整数。
const int N = 1e4 + 10;
int a[N];
inline void solve()
{
int n;
cin >> n;
cin >> a[1] >> a[2];
a[2] /= __gcd(a[1], a[2]);
for (int i = 3; i <= n; i++)
{
cin >> a[i];
a[2] /= __gcd(a[i], a[2]);
}
if (a[2] == 1)
cout << "Yes" << endl;
else
cout << "No" << endl;
}
P2660 zzc 种田
inline void solve()
{
LL x, y;
cin >> x >> y;
LL ans = 0;
while (x && y)
{
swap(x, y); // x是长,y是宽
ans += 4 * y * (x / y);
x %= y;
}
cout << ans << endl;
}
P1403 [AHOI2005] 约数研究
[1,n]里约数有i的个数是⌊n/i⌋下取整
约数表如下所示
inline void solve()
{
int n;
cin >> n;
LL ans = 0;
ff(i, n)
{
ans += n / i;
}
cout << ans;
}
优化: 很多⌊n/i⌋下取整都是一样的,i跳到⌊n/j⌋=⌊n/i⌋+1的位置
inline void solve()
{
int n, ans = 0;
cin >> n;
for (int i = 1; i <= n;)
{
int j = n / (n / i);
ans += (n / i) * (j - i + 1);
i = j + 1;
}
cout << ans;
}
P1469 找筷子
const int N = 1e7 + 10;
int a[N], b[N];
set<int> s;
inline void solve()
{
int n;
cin >> n;
ff(i, n)
{
cin >> a[i];
b[a[i]]++;
s.insert(a[i]);
}
for (auto i : s)
{
if (b[i] % 2 != 0)
{
cout << i << endl;
break;
}
}
}
空间限制为 4 Mb的时候,开一个10^7的数组就MLE了。
异或运算
异或的两个小小的性质:
- k 个相同的数的异或和,当 k 为奇数时,结果是这个数本身,否则结果是 0。
- 任何数与 0 的异或值是它本身。
inline void solve()
{
int n;
cin >> n;
int ans = 0;
ff(i, n)
{
int x;
cin >> x;
ans ^= x;
}
cout << ans;
}
P1246 编码
模拟:
inline void solve()
{
string s;
cin >> s;
int sl = s.size();
int a[8];
for (int i = 0; i < sl; i++)
a[i] = s[sl - i - 1] - 'a' + 1;
int t = 0;
int b[8] = {0};
while (++t)
{
b[0]++;
int k = 0;
for (int i = 0; i < 8; i++)
{
if (b[i] > 26 - i)
{
k++;
b[i + 1]++;
}
else
break;
}
for (int i = k - 1; i >= 0; i--)
{
b[i] = b[i + 1] + 1;
}
int flag = 0;
for (int i = 0; i < sl; i++)
{
if (a[i] != b[i])
{
flag = 1;
break;
}
}
if (flag == 0)
{
cout << t << endl;
break;
}
if (b[6])
{
cout << "0" << endl;
break;
}
}
}
打表:
map<string, int> m;
int ans = 1;
void qwe(int res, char c, string s)
{
if (res == 0)
{
m[s] = ans;
ans++;
return;
}
if (c == 'z' + 1)
return;
for (int i = 0; c + i <= 'z' - (res - 1); i++) // 要求不重复
{
qwe(res - 1, char(c + i) + 1, string(s + char(c + i)));
}
}
inline void solve()
{
qwe(1, 'a', "");
qwe(2, 'a', "");
qwe(3, 'a', "");
qwe(4, 'a', "");
qwe(5, 'a', "");
qwe(6, 'a', "");
string s;
cin >> s;
cout << m[s];
}
P2926 [USACO08DEC] Patting Heads S
const int N = 1e6 + 10;
int a[N], b[N], cnt[N];
inline void solve()
{
int n;
cin >> n;
int maxn = 0;
ff(i, n)
{
cin >> a[i];
b[a[i]]++; // 存a[i]出现的次数
maxn = max(maxn, a[i]);
}
ff(i, maxn)
{
if (b[i] == 0)
continue;
for (int j = 1; i * j <= maxn; j++)
cnt[i * j] += b[i]; // 枚举i的倍数,同j+=i;cnt[j]+=b[i];
}
ff(i, n) cout << cnt[a[i]] - 1 << endl; // 不能拍自己
}
P1835 素数密度
// 欧拉筛
const int N = 1e5 + 10;
int primes[N], cnt; // primes[]存储所有素数
bool st[N]; // st[x]存储x是否被筛掉
void get_primes(int n)
{
for (int i = 2; i <= n; i++)
{
if (!st[i])
primes[cnt++] = i;
for (int j = 0; primes[j] * i <= n; j++)
{
st[primes[j] * i] = true;
if (i % primes[j] == 0)
break;
}
}
}
// 区间范围,因为我们无法完全映射所有的区间,只能采用类似于偏移的办法对某段区间整体偏移L进行描述。
// 否则空间上的限制就先达到了,无法用计算机模拟了。
const int M = 10000010;
int a[M]; // 记录偏移后的数据是不是合数,1:合数;0:质数。a[i]表示L+i是不是合数, 有一个偏移量L
inline void solve()
{
// 筛出50000之内的所有质数
get_primes(50000); // R开根号的极限也小于50000
// 问:为啥要开LL,开INT不行吗?
// 答:不行,因为下面的运算中可能存在加法,如果是极限的整数,再加一下就会爆INT。
LL L, R;
cin >> L >> R;
// 特判,防止第11个测试点WA掉。
if (L == 1)
L = 2;
// 遍历已知的质数列表
for (int i = 0; i < cnt; i++)
{
// start:找到开始筛的数字
// 【大于L,并且是p的倍数,最小整数是多少?】
LL start = max(2ll, (L - 1) / primes[i] + 1) * primes[i];
// 成倍的质数筛出掉
for (LL j = start; j <= R; j += primes[i])
a[j - L] = 1; // 标识为质数
}
// 结果
int ans = 0;
for (LL i = L; i <= R; i++)
if (!a[i - L])
ans++;
cout << ans << endl;
}
P1414 又是毕业季II
const int N = 1e6 + 10;
int cnt[N]; // c[i]表示i作为因子的次数
inline void solve()
{
int n;
cin >> n;
int t = 0;
ff(i, n)
{
int x;
cin >> x;
t = max(t, x); // 记录目前最大能力值
for (int i = 1; i <= sqrt(x); i++)
{
if (x % i == 0) // 有约数
{
cnt[i]++; // i作为因子的次数++
if (x != i * i)
cnt[x / i]++; // 如果不是平方,x/i也是因子;如果x是i的平方只记录i作为一次因子
}
}
}
int x = t;
ff(i, n)
{
while (cnt[x] < i) // cnt[x]>=i时停止
x--;
cout << x << endl;
}
}