洛谷的专题qwqqqqq(乱序按心情做也不一定做得完= =)
三分钟热度就有三分钟的收获_(:з」∠)_
但是我永远喜欢算法
思路:先转为十进制,再转为目标进制。
转十进制:先乘再模
十转其他:先模再除
#include
#include
#include
#include
using namespace std;
int n, m, x;
char a[111];
int main()
{
cin >> n >> a >> m;
x = 0;
for(int i = 0; a[i] ;i ++)
{
x *= n;
if(a[i] >= '0' && a[i] <= '9') x += a[i] - '0';
else x += a[i] - 'A' + 10;
}
int idx = 0;
while(x)
{
int t = x % m;
x /= m;
if(t < 10) a[idx] = '0' + t;
else a[idx] = 'A' + (t - 10);
idx ++;
}
for(int i = idx - 1;i >= 0; i--) cout << a[i];
return 0;
}
思路:奇妙转为异或和
因为有内存限制,而且数据是1e7实在太多,开始是想unique离散化,然后快乐地MLE了一发(?)
理智分析,一个数异或自己就是0,就是说:x ^ x == 0 ; 再加上,0异或任何数都是任何数本身。也就是说所有输入的异或和最后就剩那个寡王。(挺妙的一开始没想到)
还有就是因为输入太多了建议1e6以上就用scanf而不是cin。
#include
#include
#include
#include
using namespace std;
int main()
{
int n, a, ans;
scanf("%d", &n);
ans = 0;
for(int i = 0;i < n; i++)
{
scanf("%d",&a);
ans ^= a;
}
printf("%d\n", ans);
return 0;
}
思路:题目说啥就写啥_(:з」∠)_
可能吗?不可能。
开始直接模拟写的,然后点了一下题解。
位运算的话好像代码会巨短!
先给出模拟的代码
顺带一提不开long long是会wa的(别问怎么知道的)
#include
#include
#include
#include
using namespace std;
typedef long long ll;
int a[66];
int main()
{
ll n;
scanf("%lld", &n);
int idx = 32;
while(n)
{
a[idx --] = n % 2;
n /= 2;
}
for(int i = 1;i <= 16; i++)
{
swap(a[i], a[16 + i]);
}
n = 0;
for(int i = 1;i <= 32; i++)
{
n *= 2;
n += a[i];
}
printf("%lld\n", n);
return 0;
}
然后是位运算的代码
思路:C++的unsigned int正好32位,所以位运算溢出的部分不需要管。
(所以涉及到二进制可以考虑一下位运算?)
#include
#include
#include
#include
using namespace std;
typedef unsigned int ui;
int main()
{
ui n;
cin >> n;
cout << (n << 16) + (n >> 16) << endl;
return 0;
}
思路:负数进制的进制转换和普通的进制转换没啥差别,主要是取余的时候会出现负数,需要处理一下,把余数变成正数,然后把补充余数的部分从原数中减掉就好啦_(:з」∠)_
#include
#include
#include
#include
using namespace std;
char a[66];
int main()
{
int n, r;
scanf("%d%d", &n, &r);
int x = n;
int idx = 0;
while(n)
{
int t = n % r;
if(t < 0)
{
n += r;
t -= r;
}
n /= r;
if(t < 10) a[idx ++] = t + '0';
else a[idx ++] = t - 10 + 'A';
}
printf("%d=", x);
for(int i = idx - 1;i >= 0; i--) printf("%c", a[i]);
printf("(base%d)", r);
return 0;
}
思路:简单贪心,有点像gcd,每次选最大的正方形除尽就好
#include
#include
#include
#include
using namespace std;
typedef unsigned long long ull;
int main()
{
ull x, y, ans;
cin >> x >> y;
ans = 0;
if(x < y) swap(x, y);
while(x && y)
{
ans += 4 * (x / y) * y;
x %= y;
swap(x, y);
}
cout << ans << endl;
return 0;
}
思路:就是很简单的求三个数的最小公倍数,最小公倍数等于两数的乘积除以最大公约数,习惯上要先除再乘防爆
#include
#include
#include
#include
using namespace std;
typedef long long ll;
ll gcd(ll x, ll y)
{
if(x % y == 0) return y;
return gcd(y, x % y);
}
int main()
{
ll a, b, c, ans;
cin >> a >> b >> c;
ans = a / gcd(a, b) * b;
ans = ans / gcd(ans, c) * c;
cout << ans << endl;
return 0;
}
思路:线性筛的核心就是说——n只会被它的最小质因子筛掉;
分为两步:
①从小到大枚举所有质数;
②每次把当前的质数和 i 的乘积筛掉;
当 i % p[j] == 0,说明 p[j] 一定是p[j] * i的最小质因子;
否则,p[j] 一定小于 i 的所有质因子,p[j] 也一定是 p[j] * i 的最小质因子;
而对于一个合数,假设 p[j] 是 x 的最小质因子,则当 i 枚举到 x / p[j] 时,x 就会被筛掉;
#include
#include
#include
#include
using namespace std;
const int maxn = 1e8 + 10;
int p[6000010], idx;
bool st[maxn];
int main()
{
int n, q, k;
scanf("%d%d", &n, &q);
idx = 0;
memset(p, 0, sizeof(p));
memset(st, 0, sizeof(st));
for(int i = 2;i <= n; i++)
{
if(!st[i]) p[idx ++] = i;
for(int j = 0;p[j] <= n / i; j++)
{
st[p[j] * i] = true;
if(i % p[j] == 0) break;
}
}
for(int i = 0;i < q; i++)
{
scanf("%d", &k);
printf("%d\n", p[k - 1]);
}
return 0;
}
思路:数据范围无比友善,所以暴力就行
因为P和Q可以交换,所以特殊处理一下完全平方数就好
#include
#include
#include
#include
using namespace std;
int gcd(int a, int b)
{
if(a % b == 0) return b;
return gcd(b, a % b);
}
int main()
{
int x, y;
cin >> x >> y;
int ans = 0;
int s = x * y;
int flag = 0;
for(int i = 1;i <= s / i; i++)
{
if(s % i == 0 && gcd(i, s / i) == x)
{
ans ++;
if(i * i == s) flag = 1;
}
}
if(flag)
{
if(ans) cout << ans * 2 - 1 << endl;
else cout << 1 << endl;
}
else cout << ans * 2 << endl;
return 0;
}
思路:很简单,和筛素数差不多的思想,就是从小到大枚举,然后把所有倍数的约数个数 + 1,加一下就好啦。
#include
#include
#include
#include
using namespace std;
const int maxn = 1e6 + 10;
int sum[maxn];
int main()
{
int n;
scanf("%d", &n);
int res = 0;
for(int i = 1;i <= n; i++)
{
for(int j = 1;j <= n / i; j++)
{
sum[i * j] ++;
}
res += sum[i];
}
printf("%d\n", res);
return 0;
}
思路:拿手模拟就行,输入直接scanf读,不用处理字符串这样麻烦。然后wa的两发的原因在于,一次没想整除,一次没想分母为负,我觉得我就是傻蛋= =,当场退役算了
#include
#include
#include
#include
using namespace std;
int gcd(int a, int b)
{
if(a % b == 0) return b;
return gcd(b, a % b);
}
int main()
{
int x, y, p, q;
scanf("%d/%d", &x, &y);
while(~scanf("%d/%d", &p, &q))
{
int k = gcd(y, q);
x = q / k * x;
p = y / k * p;
x = x + p;
y = y / k * q;
k = gcd(x, y);
x = x / k;
y = y / k;
}
if(y < 0)
{
x *= -1;
y *= -1;
}
if(x % y == 0) printf("%d\n", x / y);
else printf("%d/%d\n",x, y);
return 0;
}
思路:水题,行列总数 * n 减掉重复的点就行
#include
#include
#include
#include
using namespace std;
typedef long long ll;
const int maxn = 1e6 + 10;
int r[maxn], c[maxn];
int main()
{
int n, k;
scanf("%d%d", &n, &k);
for(int i = 1;i <= k; i++) scanf("%d%d", &r[i], &c[i]);
sort(r + 1, r + 1 + k);
sort(c + 1, c + 1 + k);
int len1 = unique(r + 1, r + 1 + k) - 1 - r;
int len2 = unique(c + 1, c + 1 + k) - 1 - c;
printf("%lld\n", (ll)n * (len1 + len2) - (ll)len1 * len2);
return 0;
}
思路:神奇的组合数叭算是
因为一共只有26个字母,且只有6位,所以可以预处理出26以内的所有组合数。对于给定编码的每一位进行讨论,因为题目规定了必须升序,所以相当于枚举每一位,然后加上合法的组合数,wa了很多发因为忘记处理首位的边界问题。
#include
#include
#include
#include
using namespace std;
char a[11];
int c[27][27];
void init()
{
for(int i = 0;i <= 26; i++)
{
for(int j = 0;j <= i; j++)
{
if(!j) c[i][j] = 1;
else c[i][j] = c[i - 1][j] + c[i - 1][j - 1];
}
}
}
int main()
{
init();
scanf("%s", a + 1);
int ans = 0;
int n = strlen(a + 1);
int flag = 0;
for(int i = 2;i <= n; i++)
{
if(a[i] <= a[i - 1])
{
flag = 1;
break;
}
}
if(flag) printf("0\n");
else
{
for(int i = 1;i < n; i++) ans += c[26][i];
for(int i = 1;i <= n; i++)
{
int j;
if(i == 1) j = 1;
else j = a[i - 1] - 'a' + 2;
while(j < a[i] - 'a' + 1)
{
ans += c[26 - j][n - i];
j++;
}
}
printf("%d\n", ans + 1);
}
return 0;
}