2022.7.28 模拟赛
T1 数据结构
第一个操作很好实现,只需要增加 即可
第二个操作是瓶颈,暴力做是不行的
瓶颈在操作 ,若是可以减少操作 的复杂度,就可以通过本题
怎么做呢?我们知道每个数到底被加了几次,就可以一次性算出它的贡献
我们每次操作 使用一个懒标记,加入 就是加入
预处理组合数,如此一来复杂度就在 了
#include <iostream>
#include <cstdio>
#define int long long
using namespace std;
inline int rd()
{
int ret = 0, f = 1;
char c;
while (c = getchar(), !isdigit(c))
f = c == '-' ? -1 : 1;
while (isdigit(c))
ret = ret * 10 + c - '0', c = getchar();
return ret * f;
}
const int MAXN = 55;
const int MOD = 1e9 + 7;
int k, m, sum[MAXN], f[MAXN][MAXN];
int s;
void solve()
{
int x, y;
y = rd();
if (y == 0)
{
x = rd() - s;
if (x < 0)
x += MOD;
int tmp = 1;
for (int i = 0; i <= k; i++)
{
(sum[i] += tmp;) %= MOD;
(tmp *= x) %= MOD;
}
}
else
s++;
int ans = 0, tmp = 1;
for (int i = k; i >= 0; i--)
{
(ans += (f[k][i] * sum[i]) % MOD * tmp % MOD) %= MOD;
(tmp *= s) %= MOD;
}
cout << ans << endl;
}
signed main()
{
m = rd();
k = rd();
f[0][0] = 1;
for (int i = 1; i <= 50; i++)
{
f[i][0] = 1;
for (int j = 1; j <= 50; j++)
{
f[i][j] = (f[i - 1][j] + f[i - 1][j - 1]) % MOD;
}
}
while (m--)
solve();
return 0;
}
T2 商店购物
考虑一个判定问题:给出一个 判断是否可行。
对于每个元素 :
若 ,则 对判定 无效
若 ,则 一定可行
若 ,需要继续讨论
我们关注小于 的 ,记它们的和 为
若 ,则 不可行
若 ,则 可行(我们找到了一种方案)
若 ,则 可行
为什么?因为每个 均小于 ,记
恒成立,故 不可能小于 而使得 不可行
若 ,则 可行(我们找到了一种方案)
若 ,那么可以继续重复此过程,直到可行
因此,只需要记录前缀和,算出所有的区间并,就是最终答案
#include <iostream>
#include <cstdio>
#define int long long
using namespace std;
const int MAXN = 100005;
int a[MAXN], n, ans;
signed main()
{
cin >> n;
for (int i = 1; i <= n; i++)
cin >> a[i];
sort(a + 1, a + 1 + n);
int sum = 0, lst = 0;
for (int i = 0; i <= n; i++)
{
sum += a[i];
while (a[i + 1] == a[i])
sum += a[++i];
ans += sum - max(lst, (a[i] + 1) / 2 - 1);
lst = sum;
}
cout << ans << endl;
return 0;
}
T3 植物大战僵尸
什么时候玩家必败?
如果存在形如 的情况,那么玩家显然必败
也就是说,如果有 个 位置的僵尸,那么玩家是必败的
我们发现,位置 的权重是 位置的一半,换句话说,后面最多只有一半的僵尸能到达下一个位置
我们可以把这个序列用每个元素的权重表示出来,如果我们认为 的权重是 的话,那么玩家必败当且仅当我们可以把序列分成两部分 ,使得 且
于是现在的问题就是,给定 个分数组成的集合,求把它们划分为两个 的集合的方案数
这样不好求,可以容斥一下,求把它们划分成至少有一个 的方案数,这就是一个背包问题了
#include <algorithm>
#include <cstring>
#include <iostream>
#include <cstdio>
#define int long long
using namespace std;
inline int rd()
{
int ret = 0, f = 1;
char c;
while (c = getchar(), !isdigit(c))
f = c == '-' ? -1 : 1;
while (isdigit(c))
ret = ret * 10 + c - '0', c = getchar();
return ret * f;
}
void _(int x)
{
if (x == 0)
return;
_(x / 10);
putchar('0' + x % 10);
}
void out(int x)
{
if (!x)
return;
_(x);
}
const int MAXN = 100005;
const int MOD = 1e9 + 7;
int T, n;
int a[MAXN], f[MAXN];
void init()
{
memset(f, 0, sizeof(f));
}
int qpow(int x, int y)
{
int ret = 1ll;
while (y)
{
if (y & 1)
(ret *= x) %= MOD;
(x *= x) %= MOD;
y >>= 1ll;
}
return ret;
}
void solve()
{
n = rd();
for (int i = 1; i <= n; i++)
a[i] = rd();
sort(a + 1, a + 1 + n);
int V = 0, cur = a[n];
f[0] = 1;
for (int i = n; i >= 1; i--)
{
int t = 1;
while (a[i] != cur)
{
t <<= 1;
cur--;
if (t > V)
{
cur = a[i];
break;
}
}
if (t > 1)
{
for (int k = 0; k <= V / t; k++)
{
int tmp = 0;
for (int j = k * t; j < min((k + 1) * t, V + 1); j++)
{
tmp += f[j];
f[j] = 0;
tmp %= MOD;
}
f[k] += tmp;
f[k] %= MOD;
}
V /= t;
}
for (int j = V; j >= 0; j--)
f[j + 1] += f[j], f[j + 1] %= MOD;
V++;
}
int up = 1, ans = 0;
while (cur > 1)
{
up <<= 1;
up = min(up, V + 1);
cur--;
}
for (int i = 0; i < up; i++)
(ans += f[i]) %= MOD;
ans = -2 * ans;
ans += qpow(2, n);
while (ans < 0)
ans += MOD;
out(ans);
putchar('\n');
}
signed main()
{
T = rd();
while (T--)
init(), solve();
return 0;
}
T4 机房的新生活委员
设 表示前 个商店买状态为 花的钱的最小值
则有转移方程
初始状态 ,其他为
最终答案为 , 时空复杂度为
#include <cstdio>
#include <cstring>
using namespace std;
#define cmin(_a, _b) (_a > (_b) ? _a = (_b) : 0)
int fee[108], cost[108][18], tmp[108], f[66600], v[66600];
int main()
{
register int n, m, i, j, S, x, _S, U, newf, newfS;
scanf("%d %d", &n, &m);
for (i = 1; i <= n; ++i)
{
scanf("%d", &fee[i]);
for (j = 0; j < m; ++j)
scanf("%d", &cost[i][j]);
}
U = (1 << m) - 1;
for (S = 1; S <= U; ++S)
{
memcpy(tmp, fee, sizeof(tmp) / 108 * (n + 1));
_S = S;
for (i = 0; _S; ++i, _S >>= 1)
{
if ((_S & 1) == 0)
continue;
for (j = 1; j <= n; ++j)
tmp[j] += cost[j][i];
}
v[S] = tmp[1];
for (i = 2; i <= n; ++i)
cmin(v[S], tmp[i]);
}
memset(f, 63, sizeof(f));
f[0] = 0;
for (S = 1; S <= U; ++S)
{
newfS = 0x3f3f3f3f;
for (x = S; x; x = S & (x - 1))
{
newf = f[S ^ x] + v[x];
cmin(newfS, newf);
}
f[S] = newfS;
}
printf("%d", f[U]);
return 0;
}
本文作者:PassName
本文链接:https://www.cnblogs.com/spaceswalker/p/16529276.html
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步