第十二届
A.空间
( ( 256 * 1024 ) * 1024 ) / 4
1 MB = 1024 KB 1KB = 1024B 1B = 8 bit位 = 8 二进制位
67108864
B.卡片
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
int main()
{
int a[10];
for(int i = 0; i <= 9; i ++ ) a[i] = 2021;
int ans = 1, i = 0;
while(true)
{
i = ans;
while(i)
{
a[i % 10] -- ;
if(a[i % 10] <= 0)
{
cout << ans << endl;
return 0;
}
i /= 10;
}
ans ++ ;
}
return 0;
}
C.直线
#include <iostream>
#include <algorithm>
#include <cmath>
#include <cstring>
using namespace std;
const int N = 200000; // 最多有 20 * 20 个点, 400 * 400 个不同组合·
int n;
struct Line // 直线方程 y = k * x + b , 用 k,b 区分不同直线
{
double k, b;
bool operator< (const Line& t) const // k, b 递增排序
{
if(k != t.k) return k < t.k;
return b < t.b;
}
}l[N]; // 用 (k, b) 区分存放不同的直线方程
int main()
{
for(int x1 = 0; x1 < 20; x1 ++ )
for(int y1 = 0; y1 < 21; y1 ++ )
for(int x2 = 0; x2 < 20; x2 ++ )
for(int y2 = 0; y2 < 21; y2 ++ )
if(x1 != x2)
{
double k = (double) (y2 - y1) / (x2 - x1);
double b = y1 - k * x1;
l[n ++ ] = {k, b};
}
sort(l, l + n);
int res = 1; // 统计不同 k, b 的直线方程有多少条
for(int i = 1; i <n; i ++ )
if(fabs(l[i].k - l[i - 1].k) > 1e-8 || fabs(l[i].b - l[i - 1].b) > 1e-8) // 部分斜率、截距之间的差值非常微小
res ++;
cout << res + 20 << endl; // 20 为 k = 0 时垂直于x轴的直线
return 0;
} // 40257
D.货物摆放
#include <iostream>
#include <vector>
typedef long long LL;
using namespace std;
int main()
{
LL n = 2021041820210418;
cin >> n;
vector<LL> d;
for(LL i = 1; i * i <= n; i ++ )
if(n % i == 0)
{
d.push_back(i);
if(n / i != i) d.push_back(n / i);
}
int res = 0;
for(auto a: d)
for(auto b: d)
for(auto c: d)
if(a * b * c == n)
res ++;
cout << res << endl;
return 0;
}
// 暴力枚举
#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
typedef long long LL;
int main()
{
LL n = 2021041820210418, res = 0;
for(LL i = 1; i <= n; i ++ )
if(n % i == 0)
for(LL j = 1; j <= n; j ++ )
if(n / i % j == 0)
{
LL k = n / i / j;
if(i == j && j == k) res ++;
else if(i != j & j != k) res += 6;
else res += 3;
}
cout << res << endl;
return 0;
}
E.路径*
… …
F.时间显示*
G.砝码称重
// DP 背包
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 110, M = 200010, B = M / 2;
int n, m;
int w[N];
bool f[N][M];
int main()
{
scanf("%d", &n);
for(int i = 1; i <= n; i ++ ) scanf("%d", &w[i]), m += w[i];
f[0][B] = true;
for (int i = 1; i <= n; i ++ )
for(int j = -m; j <= m; j ++ )
{
f[i][j + B] = f[i - 1][j + B];
if(j - w[i] >= -m) f[i][j + B] |= f[i - 1][j - w[i] + B];
if(j + w[i] <= m) f[i][j + B] |= f[i - 1][j + w[i] + B];
}
int res = 0;
for(int j = 1; j <= m; j ++ )
if(f[n][j + B])
res ++;
printf("%d\n", res);
return 0;
}
H.杨辉三角
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long LL;
int n;
/*
组合数和杨辉三角:第i行第j列的数都是组合数C(i, j) (i,j从0开始)
C(n, 1) = n --> 对应从左向右看斜着的第二列! ---> 一定有解
由于杨辉三角左右对称(C(a, b) == C(a, a-b)),又由于找第一次出现,因此一定在左边,右边可以直接删掉!
1 ---> C(0, 0)
1
1 2 ---> C(2, 1)
1 3 ---> C(2n, n)
1 4 6 ---> C(4, 2)
1 5 10
1 6 15 20 ---> C(6, 3)
n最大1e9,C(34, 17) > 1e9, C(32, 16) < 1e9,因此只要枚举前16个斜行即可!
性质:
1. 每一斜行从上到下递增
2. 每一横行从中间到两边依次递减
因此我们直接从中间对称轴倒序二分找起即可!
C(r, k)对应的顺序值为:(r + 1) * r / 2 + k + 1
二分的左右端点:l:2k,r:max(n, l)
右端点一定不能比左端点小!
特例:否则当n=1时,会出问题!
*/
// C(a, b) = a!/b!(a-b)! = a * (a-1) .. b个 / b!
LL C(int a, int b){
LL res = 1;
for(int i = a, j = 1; j <= b; i --, j ++){
res = res * i / j;
// 大于n已无意义,且防止爆LL
if(res > n) return res;
}
return res;
}
bool check(int k){
// 二分该斜行,找到大于等于该值的第一个数
// 左边界2k,右边界为max(l, n)取二者最大即可!
int l = 2 * k, r = max(n, l);
while(l < r){
int mid = l + r >> 1;
if(C(mid, k) >= n) r = mid;
else l = mid + 1;
}
if(C(r, k) != n) return false;
// C(r, k)的从0开始的顺序!
cout << 1ll * (r + 1) * r / 2 + k + 1 << endl;
return true;
}
int main(){
cin >> n;
// 从第16斜行枚举即可!
for(int k = 16; ; k --)
if(check(k)) break;
return 0;
}
I.双向排序*
J.括号序列*
第十一届
A.门牌制作
#include <bits/stdc++.h>
using namespace std;
// 1~2020需要多少个字符2
int ans = 0;
void check(int i)
{
while(i > 0)
{
if(i % 10 == 2) ans ++ ;
i /= 10;
}
}
int main()
{
for(int i = 1; i <= 2020; i ++ ) check(i);
cout << ans << endl;
return 0;
} // 624
B.既约分数
#include <bits/stdc++.h>
using namespace std;
// 1~2020有多少个既约分数的组合 不可同 / 2 3 5 7
int ans = 0;
int gcd(int a, int b)
{
/*if(a % 2 == b % 2 || a % 3 == b % 3 || a % 5 == b % 5 || a % 7 == b % 7) return;
else ans += 2 ;*/
if(a % b == 0) return b;
return gcd(b, a % b);
}
int main()
{
for(int i = 1; i <= 2020; i ++ )
for(int j = i + 1; j <= 2020; j ++ )
if(gcd(i, j) == 1) ans ++ ;
// 分子分母可互换 * 2 ; 1/1 2/2 3/3 ... 属于同一种情况 + 1
cout << ans * 2 + 1 << endl;
return 0;
} // 2481215
C.蛇形填数
#include <bits/stdc++.h>
using namespace std;
int main()
{
int x = 0;
for(int i = 1; i <= 19; i ++ ) x += i;
cout << 5 + x * 4 << endl;
} // 找规律
D.跑步锻炼
#include <bits/stdc++.h>
using namespace std;
int days[13] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
int main()
{
int day = 1, month = 1, year = 2000, weekday =6, cnt = 0;
while(1)
{
cnt += (day == 1 || weekday == 1) + 1; // 周一或月初 +1
if(year == 2020 && month == 10 && day == 1) break;
day ++ ;
weekday = (weekday + 1) % 7;
if(month == 2 && (year % 4 == 0 && year % 100 != 0 || year % 400 == 0)) // 二月并且是闰年
{
if(day > days[month] + 1) // 29号后遍历下一个月
{
day = 1;
month ++ ;
}
}
else if(day > days[month])
{
day = 1;a
month ++ ;
}
if(month == 13)
{
year ++ ;
month = 1;
}
}
cout << cnt << endl;
return 0;
}
E.七段码*
F.成绩统计
#include <bits/stdc++.h>
using namespace std;
int a[10010];
int n;
int main()
{
cin >> n;
int qsum = 0, esum = 0;
for(int i = 1; i <= n; i ++ )
{
cin >> a[i];
if(a[i] >= 60) qsum ++ ;
if(a[i] >= 85) esum ++ ;
}
int q_sum = (qsum * 1000 / n) , e_sum = (esum * 1000 / n);
if(q_sum % 10 >= 5) q_sum += 10;
if(e_sum % 10 >= 5) e_sum += 10;
cout << q_sum / 10 << "%" << endl << e_sum / 10 << "%" << endl;
return 0;
}
整除序列
#include <iostream>
using namespace std;
int main()
{
long long n;
cin >> n;
while(n)
{
cout << n << ' ';
n /= 2;
}
return 0;
}// 3181
解码
#include <iostream>
#include <cstring>
using namespace std;
int main()
{
string s, res; // s存放每次读入的字符串, res 存放最终输出的字符串结果
cin >> s;
for(int i = 0; i < s.size(); i ++ )
{
if(i + 1 < s.size() && s[i + 1] <= '9') // 任何一个大小写英文字母的ascii码都 >'9'
{
int k = s[i + 1] - '0'; // 存放数字--循环打印s[i]字符的次数
while(k -- ) res += s[i];
i ++; // 字符 s[i] 打印 s[i + 1] 次后继续遍历下一个字符
}
else res += s[i]; // s[i + 1] 处不是数字,字符s[i]仅打印一次则直接加入
}
cout << res << endl;
return 0;
}
走方格
#include <iostream>
#include <cstring>
using namespace std;
const int N = 40;
int f[N][N]; // f[i][j] 表示从起点走到 (i, j) 共有多少种方案
int n, m;
int main()
{
cin >> n >> m;
f[1][1] = 1; // 最开始在格子1,方案数为1
for(int i = 1; i <= n; i ++ )
for(int j = 1; j <= m; j ++ )
{
if(i == 1 && j == 1) continue;
if(i % 2 || j % 2) //保证行列不能同时为偶数 (i % 2 || j % 2) 其中两个条件都为偶数则 0
f[i][j] = f[i - 1][j] + f[i][j - 1];
}
cout << f[n][m] << endl;
return 0;
}