上午刚打完,下面放的 全部都是考场代码(除了I题是之后补的,考的时候 漏看一个条件)。下面讲讲大致的做法
A
直接模拟
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
#include <cctype>
#include <cstring>
#include <iostream>
using namespace std;
template <typename T> inline void read(T &x)
{
x = 0;
int f = 1;
char c = getchar();
for(;!isdigit(c);c = getchar())if(c == '-')f = -f;
for(; isdigit(c);c = getchar())x = 10 * x + c - '0';
x *= f;
}
typedef long long ll;
typedef pair<int,int> PII;
int main()
{
int res = 0;
string s;
cin >> s;
int jiu = 1;
for(int i = (int)s.size() - 1;i >= 0;i --)
{
res += jiu * (s[i] - '0');
jiu *= 9;
}
printf("%d\n",res);
return 0;
}
B
题意有歧义。还是模拟。
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
#include <cctype>
#include <iostream>
using namespace std;
template <typename T> inline void read(T &x)
{
x = 0;
int f = 1;
char c = getchar();
for(;!isdigit(c);c = getchar())if(c == '-')f = -f;
for(; isdigit(c);c = getchar())x = 10 * x + c - '0';
x *= f;
}
typedef long long ll;
typedef pair<int,int> PII;
bool ck(string str)
{
for(int i = 0;i + 2 < (int)str.size();i ++)
{
if(str[i] > '0' && str[i + 1] == str[i] + 1 && str[i + 2] == str[i] + 2)return true;
//if(str[i + 1] == str[i] - 1 && str[i + 2] == str[i] - 2)return true;
}
return false;
}
string year = "2022";
string toStr(int x)
{
string rt = "";
while(x)
{
rt.push_back(x % 10 + '0');
x /= 10;
}
while(rt.size() < 2)rt.push_back(0 + '0');
reverse(rt.begin(),rt.end());
return rt;
}
int cnt[13] = {0,31,28,31,30,31,30,31,31,30,31,30,31};
int main()
{
int ans = 0;
for(int i = 1;i <= 12;i ++)
{
for(int j = 1;j <= cnt[i];j ++)
{
string month = toStr(i);
string tmp = year + month + toStr(j);
if(ck(tmp))
{
ans ++;
cout << tmp << "\n";
}
//cout << tmp << "\n";
}
}
printf("ans = %d",ans);
return 0;
}
C
直接算天数。
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
#include <cctype>
using namespace std;
template <typename T> inline void read(T &x)
{
x = 0;
int f = 1;
char c = getchar();
for(;!isdigit(c);c = getchar())if(c == '-')f = -f;
for(; isdigit(c);c = getchar())x = 10 * x + c - '0';
x *= f;
}
typedef long long ll;
typedef pair<int,int> PII;
int main()
{
ll a,b,n;
read(a),read(b),read(n);
ll week = n / (5 * a + 2 * b);
ll cur = week * (5 * a + 2 * b);
ll ans = week * 7;
vector<ll> task = {a,a,a,a,a,b,b,a,a};
for(int i = 0;i < 7;i ++)
{
if(cur >= n)
{
break;
}
cur += task[i];
ans ++;
}
printf("%lld\n",ans);
return 0;
}
D
找规律,数列是对称的。
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
#include <cctype>
using namespace std;
template <typename T> inline void read(T &x)
{
x = 0;
int f = 1;
char c = getchar();
for(;!isdigit(c);c = getchar())if(c == '-')f = -f;
for(; isdigit(c);c = getchar())x = 10 * x + c - '0';
x *= f;
}
typedef long long ll;
typedef pair<int,int> PII;
int main()
{
int n;
read(n);
for(int i = 1;i <= n;i ++)
{
int x = 2 * (i - 1);
int y = 2 * (n - i);
printf("%d\n",max(x,y));
}
return 0;
}
E
由于题目保证了 A 不小于 B,因此对每一位的进制,选取合法的最小进制即可。
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
#include <cctype>
using namespace std;
template <typename T> inline void read(T &x)
{
x = 0;
int f = 1;
char c = getchar();
for(;!isdigit(c);c = getchar())if(c == '-')f = -f;
for(; isdigit(c);c = getchar())x = 10 * x + c - '0';
x *= f;
}
typedef long long ll;
typedef pair<int,int> PII;
const int N = 1e5 + 55,MOD = 1000000007;
ll a[N],b[N],p[N],mp[N];
int n;
int ma,mb;
int main()
{
read(n);
read(ma);
for(int i = ma - 1;i >= 0;i --)read(a[i]);
read(mb);
for(int i = mb - 1;i >= 0;i --)read(b[i]);
for(int i = ma - 1;i >= 0;i --)p[i] = max(max(a[i],b[i]) + 1,2LL);
mp[0] = p[0];
for(int i = 1;i < N - 10;i ++)mp[i] = mp[i - 1] * p[i] % MOD;
ll res = 0;
for(int i = ma - 1;i >= 0;i --)
{
ll ps;
if(i == 0)ps = 1;
else ps = mp[i - 1];
ps = ps * (a[i] - b[i]) % MOD;
res = (res + ps) % MOD;
res = (res % MOD + MOD) % MOD;
}
printf("%lld\n",res);
return 0;
}
F
二维前缀和,枚举左上角顶点,再枚举另一条水平线 或 竖直线,由于所有值都非负,因此可以二分答案 ,n3logn, 可能会t。
也可以考虑 枚举矩形的两条边,再对另外两条边 运用双指针算法, n3 肯定不会t。
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
#include <cctype>
using namespace std;
template <typename T> inline void read(T &x)
{
x = 0;
int f = 1;
char c = getchar();
for(;!isdigit(c);c = getchar())if(c == '-')f = -f;
for(; isdigit(c);c = getchar())x = 10 * x + c - '0';
x *= f;
}
typedef long long ll;
typedef pair<int,int> PII;
const int N = 505;
int n,m,K;
int a[N][N];
int sum[N][N];
inline int getSum(int i,int j,int x,int y)
{
if(i > x || j > y)return 0;
return sum[x][y] - sum[x][j - 1] - sum[i - 1][y] + sum[i - 1][j - 1];
}
int main()
{
read(n),read(m),read(K);
for(int i = 1;i <= n;i ++)
{
for(int j = 1;j <= m;j ++)
{
read(a[i][j]);
}
}
for(int i = 1;i <= n;i ++)
{
for(int j = 1;j <= m;j ++)
{
sum[i][j] = sum[i][j - 1] + sum[i - 1][j] - sum[i - 1][j - 1] + a[i][j];
}
}
ll ans = 0;
for(int i = 1;i <= n;i ++)
{
for(int j = 1;j <= m;j ++)
{
for(int k = i;k <= n;k ++)
{
int l = j - 1,r = m;
while(l < r)
{
int mid = (l + r + 1) >> 1;
int sum = getSum(i,j,k,mid);
if(sum <= K)l = mid;
else r = mid - 1;
}
ans += 1LL * (l - j + 1);
}
}
}
printf("%lld\n",ans);
return 0;
}
G,洛谷P1990原题,我分了大概六种情况,维护a,b,c,d,e,f的递推关系,时间复杂度和空间复杂度都是O(6n),n 约为 1e7,刚好卡过。(交洛谷上测试之后,实际使用内存大概230MB)。
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
#include <cctype>
using namespace std;
template <typename T> inline void read(T &x)
{
x = 0;
int f = 1;
char c = getchar();
for(;!isdigit(c);c = getchar())if(c == '-')f = -f;
for(; isdigit(c);c = getchar())x = 10 * x + c - '0';
x *= f;
}
typedef long long ll;
typedef pair<int,int> PII;
//-------------------------
const int MOD = 1000000007;
const int N = 10000005;
int a[N],b[N],c[N],d[N],e[N],f[N];
signed main()
{
int n;
read(n);
a[1] = 1;
a[2] = 1,b[2] = 0,c[2] = 2,d[2] = 1;
a[3] = 2,b[3] = 2,c[3] = 2,d[3] = 1,e[3] = 0,f[3] = 2;
for(int i = 4;i <= n; i++)
{
a[i] = ((ll)a[i - 1] + b[i - 1] + d[i - 1]) % MOD;
b[i] = ((ll)c[i - 1] + e[i - 1] + f[i - 1]) % MOD;
c[i] = (2 * ((ll)a[i - 2] + b[i - 2] + d[i - 2])) % MOD;
d[i] = ((ll)a[i - 2] + b[i - 2] + d[i - 2]) % MOD;
e[i] = ((ll)c[i - 2] + e[i - 2] + f[i - 2]) % MOD;
f[i] = (2 * ((ll)a[i - 3] + b[i - 3] + d[i - 3])) % MOD;
}
int ans = ((ll)a[n] + b[n] + d[n]) % MOD;
ans = (ans % MOD + MOD) % MOD;
printf("%d\n",ans);
return 0;
}
H
题目有歧义,没规定火箭的发射顺序(这个我考试的时候没有考虑,直接默认所有火箭按编号顺序发射),那么直接dfs即可,用一个map维护剩余炸弹,枚举每个炸弹 or 火箭 辐射范围内的 所有炸弹,时间复杂度O(r3(n + m)logn)可能会 t
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
#include <cctype>
#include <map>
using namespace std;
template <typename T> inline void read(T &x)
{
x = 0;
int f = 1;
char c = getchar();
for(;!isdigit(c);c = getchar())if(c == '-')f = -f;
for(; isdigit(c);c = getchar())x = 10 * x + c - '0';
x *= f;
}
typedef long long ll;
typedef pair<ll,ll> PII;
typedef pair<pair<ll,ll>,ll> PIII;
//距离注意开 long long
map<PIII,int> cnt;
int n,m;
inline ll dis2(ll x,ll y,ll ox,ll oy)
{
return (x - ox) * (x - ox) + (y - oy) * (y - oy);
}
int ans = 0;
void dfs(ll x,ll y,ll r)
{
if(cnt[{{x,y},r}] == 0)return ;
ans += cnt[{{x,y},r}];
cnt[{{x,y},r}] = 0;
for(int i = x - r;i <= x + r;i ++)
{
for(int j = y - r;j <= y + r;j ++)
{
if(dis2(i,j,x,y) > r * r)continue;
for(int k = 0;k <= r;k ++)
dfs(i,j,k);
}
}
}
inline void solve(ll x,ll y,ll r)
{
for(int i = x - r;i <= x + r;i ++)
{
for(int j = y - r;j <= y + r;j ++)
{
if(dis2(i,j,x,y) > r * r)continue;
for(int k = 0;k <= r;k ++)
{
dfs(i,j,k);
}
}
}
}
int main()
{
read(n),read(m);
for(int i = 1;i <= n;i ++)
{
ll x,y,r;
read(x),read(y),read(r);
cnt[{{x,y},r}] ++;
}
for(int i = 1;i <= m;i ++)
{
ll x,y,r;
read(x),read(y),read(r);
solve(x,y,r);
}
printf("%d\n",ans);
return 0;
}
I
一开始没有发现 所有的酒都要喝完 这个条件,卡了好久,越想越复杂(因为酒量可能非常大),
考试结束前10分钟,写了个暴力才发现题目看错了(样例都没过)。
正解是dp:
4维 dp(i, state, j, k)
i:当前第i个地方
state:0 or 1 当前这个地方是喝酒(0)还是买酒(1)
j,当前这个地方,身上还剩余的酒量
k,走到当前这个地方,已经买了 k 次酒;
由于最后要喝完,因此 j 不大于 m,
直接dp即可(注意转移顺序)
注意边界;
答案是f[n + m][ 0 ][ 0 ][ n ]。
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
#include <cctype>
using namespace std;
template <typename T> inline void read(T &x)
{
x = 0;
int f = 1;
char c = getchar();
for(;!isdigit(c);c = getchar())if(c == '-')f = -f;
for(; isdigit(c);c = getchar())x = 10 * x + c - '0';
x *= f;
}
typedef long long ll;
typedef pair<int,int> PII;
const int MOD = 1e9 + 7,N = 209;
int n,m;
ll f[N][2][N][N];
int main()
{
read(n),read(m);
f[1][0][1][0] = 1,f[1][1][4][1] = 1;
for(int i = 2;i <= n + m;i ++)
{
for(int j = m + 1;j >= 0;j --)
{
for(int k = 1;k <= n;k ++)
f[i][0][j][k] = (f[i - 1][0][j + 1][k] + f[i - 1][1][j + 1][k]) % MOD;
}
for(int j = 0;j <= m + 1;j ++)
{
for(int k = 1;k <= n;k ++)
if(j % 2 == 0)f[i][1][j][k] = (f[i - 1][0][j / 2][k - 1] + f[i - 1][1][j / 2][k - 1]) % MOD;
}
}
printf("%lld\n",f[n + m][0][0][n]);
return 0;
}
I(考场代码)
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
#include <cctype>
using namespace std;
template <typename T> inline void read(T &x)
{
x = 0;
int f = 1;
char c = getchar();
for(;!isdigit(c);c = getchar())if(c == '-')f = -f;
for(; isdigit(c);c = getchar())x = 10 * x + c - '0';
x *= f;
}
typedef long long ll;
typedef pair<int,int> PII;
int n,m;
ll ans = 0;
bool ck(int x)
{
vector<int> a(m + n,0);
for(int i = 0;i < m + n;i ++)
{
a[i] = x % 2;
x >>= 1;
}
if(a[m + n - 1] == 1)return false;
ll cur = 2;
int num0 = 0;
for(int i = 0;i < m + n;i ++)
{
num0 += a[i] == 0;
}
if(num0 != m)return false;
for(int i = 0;i < m + n;i ++)
{
if(a[i] == 0)cur --;
else cur *= 2LL;
if(cur < 0)return false;
}
if(cur != 0)return false;
/*
for(auto p:a)printf("%d",p);
puts("");
*/
return true;
}
int main()
{
read(n),read(m);
for(int i = 0;i < 1 << (n + m);i ++)
{
if(ck(i))ans++;
}
printf("%lld\n",ans);
return 0;
}
J
很长时间都没写的数据结构题。
做法很多,这里写了一个维护最值 和 区间修改的线段树。
首先 开根号操作是非常快的,1e18 变成1 需要的次数大概不超过10次。
其次,每次肯定是选 全是最大值的 某一段进行开根号,
因此我们只需要做到(1)维护区间修改(2)查询哪一段是区间最大值
(1)容易维护
(2)等价于求所有 最大值连续段 的端点,设整个区间[1,n]最大值是ma,
先从左到右找出第一个L满足max(1,L) = ma,L为左端点。
再从L开始从左向右找出最后一个R满足min(L,R) = ma,R为右端点
那么[L,R]就是符合要求的一段。
由于总的修改次数 正比于 n,因此二分找区间的次数也正比于n
因此时间复杂度为 O(nlognlogn)
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
#include <cctype>
using namespace std;
template <typename T> inline void read(T &x)
{
x = 0;
int f = 1;
char c = getchar();
for(;!isdigit(c);c = getchar())if(c == '-')f = -f;
for(; isdigit(c);c = getchar())x = 10 * x + c - '0';
x *= f;
}
typedef long long ll;
typedef pair<int,int> PII;
const int N = 2e5 + 550;
const ll INF = 4e18;
struct Node
{
int l,r;
ll ma;
ll mi;
ll add;
}tr[N * 4];
#define ls(x) x << 1
#define rs(x) x << 1 | 1
int n;
ll h[N];
inline void pushup(int u)
{
tr[u].ma = max(tr[ls(u)].ma,tr[rs(u)].ma);
tr[u].mi = min(tr[ls(u)].mi,tr[rs(u)].mi);
}
void build(int u,int l,int r)
{
tr[u].l = l,tr[u].r = r;
if(l == r) return ;
int mid = (l + r) >> 1;
build(ls(u),l,mid),build(rs(u),mid + 1,r);
}
inline void makeAdd(int u,ll c)
{
tr[u].ma += c;
tr[u].add += c;
tr[u].mi += c;
}
inline void pushdown(int u)
{
if(tr[u].add == 0)return ;
makeAdd(ls(u),tr[u].add);
makeAdd(rs(u),tr[u].add);
tr[u].add = 0;
}
void modify(int u,int ql,int qr,ll c)// +c
{
if(ql > qr)return ;
if(tr[u].l >= ql && tr[u].r <= qr)
{
makeAdd(u,c);
return ;
}
pushdown(u);
int mid = (tr[u].l + tr[u].r) >> 1;
if(ql <= mid)modify(ls(u),ql,qr,c);
if(qr > mid)modify(rs(u),ql,qr,c);
pushup(u);
}
ll querymax(int u,int ql,int qr)
{
if(ql > qr)return 0;
if(tr[u].l >= ql && tr[u].r <= qr)return tr[u].ma;
pushdown(u);
int mid = (tr[u].l + tr[u].r) >> 1;
ll rt = 0;
if(ql <= mid)rt = max(rt,querymax(ls(u),ql,qr));
if(qr > mid)rt = max(rt,querymax(rs(u),ql,qr));
return rt;
}
ll querymin(int u,int ql,int qr)
{
if(ql > qr)return INF;
if(tr[u].l >= ql && tr[u].r <= qr)return tr[u].mi;
pushdown(u);
int mid = (tr[u].l + tr[u].r) >> 1;
ll rt = INF;
if(ql <= mid)rt = min(rt,querymin(ls(u),ql,qr));
if(qr > mid)rt = min(rt,querymin(rs(u),ql,qr));
return rt;
}
#include <cmath>
inline ll f(ll x)
{
return (ll)sqrt(x / 2 + 1);
}
int ans = 0;
void solve()
{
int p = 0;
ll ma = querymax(1,1,n);
ll tt = f(ma);
ll delta = tt - ma;
for(;p <= n;)
{
if(querymax(1,1,n) < ma)break;
int l = p + 1,r = n + 1;
if(l > n)break;
while(l < r)
{
int mid = (l + r) >> 1;
if(querymax(1,p + 1, mid) == ma)r = mid;
else l = mid + 1;
}
int L = l;//L 第一个最大值为ma的点
if(L == n + 1)continue;
l = L,r = n + 1;
while(l < r)
{
int mid = (l + r + 1) >> 1;
if(querymin(1,L,mid) != ma)r = mid - 1;
else l = mid;
}
int R = l;//第一个最小值不是ma的点
if(R == n + 1)continue;
if(R < L)continue;
modify(1,L,R,delta);
ans ++;
p = R;
}
}
int main()
{
read(n);
for(int i = 1;i <= n;i ++)read(h[i]);
build(1,1,n + 1);
for(int i = 1;i <= n;i ++)modify(1,i,i,h[i]);
while(querymax(1,1,n) > 1)
{
solve();
}
printf("%d\n",ans);
return 0;
}