CF1307(模拟赛记录)
偶然发现一道做过的 G;C 的罚时:没开 longlong,谨记。
然后一个小时没想出 E ……
E 题面:
在一年成功的牛奶生产后,Farmer John 奖励他的奶牛们它们最喜欢的美味的草。
在田里有
- Farmer John 会按照指定的顺序依次喂奶牛。
- 在奶牛被喂的时候,它会径直从一端走向另一端,一路上把甜味
和它喜爱的甜味 相同的草吃掉。 - 当它恰好吃了
单位的草,它会立即在原地停止不动并睡觉,这会使得其它奶牛无法通过这个位置(不论来自哪一侧)。 - 如果一个奶牛遇到了一个睡着的奶牛或者它走到了整行草的最末尾都没有吃饱,那么它就会变得沮丧。Farmer John 绝对不想让任何奶牛变得沮丧。
注意草不会长回来。并且为了防止奶牛沮丧,Farmer John 不必保证喂了所有奶牛。
惊人的是,Farmer John 已经发现睡着的奶牛是最满足的。如果 Farmer John 安排的最优。求出最多的睡着的奶牛数,并求出在此情况下有多少种左右两侧奶牛的方案 Farmer John 可以选择(对
赛时一直执着于 "牛的终止位置应该递减"、"同口味的牛不能一起出现" 并依次 DP,根本没有想到在口味的集合固定的时候,排列的顺序也是固定的;同时也同样只想着按照草的口味顺序枚举,根本没有想到枚举左边队列的终止位置。
在一个错误的思路上越走越深,以至于完全没有想着回头尝试一下别的方向。
下面是 E 的正解。
注意到草的口味之间是独立的:当决定了集合里包含哪些牛之后,牛的排列顺序只有一种(这代表不需要乘以某个贡献了)。这启发我们把口味之间分开看,不论每个口味内部选出了怎么样的牛,总能找到且仅有一种排列顺序是合法的。
考虑枚举左边的牛最右到达的位置
先考虑口味
预处理
则左边恰好能吃到
如果
当
再考虑其他口味
如果
如果
当
以上就是对一个固定的分界点
最后特判左边不进牛的情况。
upd:会被卡空间 …… 注意到每次只会用到
点击查看代码
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 5005, MOD = 1e9 + 7;
int n, m;
int s[N];
int pfx[N] = {}, suf[N] = {}, cnt[N][N] = {{}};
//pfx[i]:口味i在s[1~now]有多少个
//cnt[i][j]:口味i,饥饿度<=j的有多少头牛
int f[N], h[N];
int ans_slp = 0, ans_cnt = 0;
int main() {
cin >> n >> m;
for (int i = 1; i <= n; i++) {
scanf("%d", &s[i]);
suf[s[i]]++;
}
for (int i = 1; i <= m; i++) {
scanf("%d%d", &f[i], &h[i]);
cnt[f[i]][h[i]]++;
cnt[f[i]][n + 1]--;
}
for (int i = 1; i <= n; i++)
for (int j = 1; j <= n; j++)
cnt[i][j] += cnt[i][j - 1];
for (ll i = 1, slp, c, l, r; i <= n; i++) { //左边的牛恰好到i
pfx[s[i]]++;
suf[s[i]]--;
slp = 0, c = 1;
l = cnt[s[i]][pfx[s[i]]] - cnt[s[i]][pfx[s[i]] - 1];
r = cnt[s[i]][suf[s[i]]] - (suf[s[i]] >= pfx[s[i]] ? 1 : 0);
// cout << i << ':' << l << ',' << r << endl;
if (l == 0)
continue;
else if (r == 0)
slp++, c = c * l % MOD;
else
slp += 2, c = c * l % MOD * r % MOD;
for (int j = 1; j <= n; j++) {
if (j == s[i])
continue;
l = cnt[j][pfx[j]];
r = cnt[j][suf[j]];
if (!l && !r)
;
else if (l == 0 || r == 0)
slp++, c = c * (l + r) % MOD;
else if (l == 1 && r == 1)
slp++, c = c * 2 % MOD;
else
slp += 2, c = c * ((l * r % MOD - min(l, r) + MOD) % MOD) % MOD;
// cout << j << ':' << slp << ' ';
}
// cout << slp << ',' << c <<"!" << endl;
if (slp > ans_slp)
ans_slp = slp, ans_cnt = c;
else if (slp == ans_slp)
ans_cnt = (ans_cnt + c) % MOD;
}
//特殊处理:左边不进牛,只从右边进
ll tmp = 0, tmp_cnt = 1;
for (int i = 1; i <= n; i++) {
if (cnt[i][pfx[i]])
tmp++, tmp_cnt = tmp_cnt * cnt[i][pfx[i]] % MOD;
}
if (tmp > ans_slp)
ans_slp = tmp, ans_cnt = tmp_cnt;
else if (tmp == ans_slp)
ans_cnt = (ans_cnt + tmp_cnt) % MOD;
if (ans_slp)
cout << ans_slp << ' ' << ans_cnt << endl;
else
puts("0 1");
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!