刷题记录
代码在4.15号更新
代码
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long LL;
int main(){
LL a, b, n; cin >> a >> b >> n;
LL x = 5 * a + 2 * b;
LL zh = n / x;
LL da = zh * 7;
n = n % x;
LL d[7] = {a, a, a, a, a, b, b};
for (int i = 0; i < 7; i ++ ){
if(n <= 0) break;
n -= d[i];
da ++;
}
cout << da << endl;
return 0;
}
修建灌木
代码
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
int main(){
int n; cin >> n;
for (int i = 1; i <= n; i ++ ){
cout << max(i - 1, n - i) * 2 << endl;
}
return 0;
}
X进制减法
代码
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long LL;
const int N = 1e5 + 10, mod = 1e9 + 7;
int a[N], b[N];
int m1, m2;
int main(){
int n; cin >> n;
cin >> m1;
for (int i = m1 - 1; i >= 0; i -- ) cin >> a[i];
cin >> m2;
for (int i = m2 - 1; i >= 0; i -- ) cin >> b[i];
int m = max(m1, m2); //高位补0
//秦九韶算法
int ans = 0;
for (int i = m - 1; i >= 0; i -- ){
ans = (ans * (LL)max({a[i] + 1, b[i] + 1, 2}) + (a[i] - b[i])) % mod;
}
cout << ans << endl;
return 0;
}
统计子矩阵
代码1
矩阵前缀和
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long LL;
const int N = 555;
int g[N][N];
int get(int x1, int y1, int x2, int y2){
return g[x2][y2] - g[x2][y1 - 1] - g[x1 - 1][y2] + g[x1 - 1][y1 - 1];
}
int main(){
int n, m, k; cin >> n >> m >> k;
for (int i = 1; i <= n; i ++ ){
for (int j = 1; j <= m; j ++ ){
cin >> g[i][j];
//计算前缀和
g[i][j] += g[i - 1][j] + g[i][j - 1] - g[i - 1][j - 1];
}
}
LL res = 0;
//i, j枚举上界和下届, l, r枚举左界和右界
for (int i = 1; i <= n; i ++ ){
for (int j = i; j <= n; j ++ ){
for (int l = 1, r = 1, sum = 0; r <= m; r ++ ){
while(l <= r && get(i, l, j, r) > k) l ++;
res += r - l + 1;
}
}
}
cout << res << endl;
return 0;
}
代码2
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long LL;
const int N = 555;
int g[N][N];
int main(){
int n, m, k; cin >> n >> m >> k;
for (int i = 1; i <= n; i ++ ){
for (int j = 1; j <= m; j ++ ){
cin >> g[i][j];
//计算每一列的前缀和
//1 2 3 4 1 2 3 4
//5 6 7 8 6 8 10 12
//9 10 11 12 15 18 21 24
g[i][j] += g[i - 1][j];
}
}
LL res = 0;
//i, j枚举上界和下届, l, r枚举左界和右界
for (int i = 1; i <= n; i ++ ){
for (int j = i; j <= n; j ++ ){
for (int l = 1, r = 1, sum = 0; r <= m; r ++ ){
sum += g[j][r] - g[i - 1][r];
while(sum > k){
sum -= (g[j][l] - g[i - 1][l]);
l ++;
}
res += r - l + 1;
}
}
}
cout << res << endl;
return 0;
}
积木画
代码
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
int g[4][4] = {
{1, 1, 1, 1},
{0, 0, 1, 1},
{0, 1, 0, 1},
{1, 0, 0, 0},
};
const int N = 1e7 + 10, mod = 1e9 + 7;
int f[N][4];
//f[i][j]表示前i-1个列都已经填满,并且第i列当前的状态为j时有多少种方案
//状压dp,第一行表示为二进制的低位,第二行为二进制的高位
int main(){
int n; cin >> n;
//初始状态赋初值
f[1][0] = 1;
for (int i = 1; i <= n; i ++ ){
for (int j = 0; j < 4; j ++ ){ //j, k枚举的都是状态
for (int k = 0; k < 4; k ++ ){
//f[i][j] * g[j][k]表示从状态j能否变到状态k,如果可以就会累加结果并除于
f[i + 1][k] = (f[i + 1][k] + f[i][j] * g[j][k]) % mod;
}
}
}
cout << f[n + 1][0] << endl;
return 0;
}
扫雷
代码
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long LL;
const int N = 50010, M = 999997; //(5e4 + 5e4) * 10,这里hash表开大了约雷和火箭的十倍,取了一个质数
int n, m;
struct Circle
{
int x, y, r;
}cir[N];
LL h[M]; //hash数组
int id[M];
bool st[M];
//转化成一个1e9+1进制的数字
LL get_key(int x, int y)
{
return x * 1000000001ll + y; //ll是表示它1e9+1是一个long long型的数字
}
//手写hash
int find(int x, int y)
{
//将坐标(x, y)转化成一个1e9+1进制的数key
LL key = get_key(x, y);
//将key映射成999997(M)以内的数t
int t = (key % M + M) % M; //避免key为负数
//如果映射的t被用过,并且不是同样映射为t的不是当前的key,那就循环找到没有被用过的t
while (h[t] != -1 && h[t] != key)
if ( ++ t == M)
t = 0;
return t;
}
int sqr(int x)
{
return x * x;
}
void dfs(int x, int y, int r)
{
st[find(x, y)] = true; //标记,表示雷炸啦
//深搜该雷半径以内其他雷是否会牵连被炸
for (int i = x - r; i <= x + r; i ++ )
for (int j = y - r; j <= y + r; j ++ )
if (sqr(i - x) + sqr(j - y) <= sqr(r))
{
int t = find(i, j);
if (id[t] && !st[t])
dfs(i, j, cir[id[t]].r);
}
}
int main()
{
scanf("%d%d", &n, &m);
//初始化
memset(h, -1, sizeof h);
for (int i = 1; i <= n; i ++ )
{
int x, y, r;
scanf("%d%d%d", &x, &y, &r);
cir[i] = {x, y, r};
int t = find(x, y);
if (h[t] == -1) h[t] = get_key(x, y);
//如果t点之前没有雷,或者之前雷的半径要小于当前雷的,那就更新t点的雷
if (!id[t] || cir[id[t]].r < r)
id[t] = i;
}
while (m -- ) //枚举火箭
{
int x, y, r;
scanf("%d%d%d", &x, &y, &r);
//方块式枚举,因为半径小于等于10,所以直接暴力枚举
for (int i = x - r; i <= x + r; i ++ )
for (int j = y - r; j <= y + r; j ++ )
//枚举的是方块,所以要判断枚举的点是否在半径内,pow太费时间啦
if (sqr(i - x) + sqr(j - y) <= sqr(r))
{
int t = find(i, j);
if (id[t] && !st[t]) //如果t点有雷,并且之前没有被炸过,那就深搜
dfs(i, j, cir[id[t]].r);
}
}
int res = 0;
for (int i = 1; i <= n; i ++ )
if (st[find(cir[i].x, cir[i].y)]) //如果雷炸过就++
res ++ ;
printf("%d\n", res);
return 0;
}
李白打酒加强版
代码
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 111, mod = 1e9 + 7;
int f[N][N][N];
int main(){
int n, m; cin >> n >> m;
//dp
//f[i][j][k]当前遇到i家店,j朵花,且酒剩余k单位,的方案数
//状态计算:当前在花:f[i][j - 1][k + 1];当前在店f[i - 1][j][k / 2];(k % 2 == 0)
//因为最后一定是遇到花,把酒喝完,所以剩余的酒一定是小于等于剩余花的数量,确保它能喝完
f[0][0][2] = 1;
for (int i = 0; i <= n; i ++ ){
for (int j = 0; j <= m; j ++ ){
for (int k = 0; k <= m - j + 1; k ++ ){
if(i && k % 2 == 0) f[i][j][k] = (f[i][j][k] + f[i - 1][j][k / 2]) % mod;
if(j) f[i][j][k] = (f[i][j][k] + f[i][j - 1][k + 1]) % mod;
}
}
}
cout << f[n][m - 1][1];
return 0;
}
砍竹子
代码
#include <iostream>
#include <cstring>
#include <algorithm>
#include <stack>
#include <cmath>
using namespace std;
typedef long long LL;
const int N = 200010, M = 10;
LL f[N][M];
int main()
{
int n, m = 0; cin >> n;
stack<LL> stk;
int res = 0;
for (int i = 0; i < n; i ++ )
{
LL x; cin >> x;
while (x > 1) stk.push(x), x = sqrt(x / 2 + 1);
res += stk.size();
m = max(m, (int)stk.size()); //记录砍竹子的最高层
for (int j = 0; stk.size(); j ++)
f[i][j] = stk.top(), stk.pop(); //存每一层
}
for (int i = 0; i < m; i ++ )
for (int j = 1; j < n; j ++ )
//如果与前一棵竹子有相同的砍的路径,那就可以一起砍,也就可以合并在一起
//一层一层的枚举
if (f[j][i] && f[j][i] == f[j - 1][i])
res -- ;
cout << res << endl;
return 0;
}
以上题目图片和链接都来自acwing