2024.09.17模拟赛总结
破防了破防了破防了破防了破防了破防了破防了破防了破防了破防了破防了破防了破防了破防了破防了破防了破防了破防了破防了破防了破防了破防了破防了破防了破防了
难度整体波动,局部递增。
怎么每次
想了大半场比赛,结果还没做出来,要是换成
似乎被样例
首先考虑 spj 判断答案是否正确的过程,大概是贪心的往后找,直接判,如下:
int x=0,y=0,ba=0;
for(auto c:w) {
while(x<a.size()&&a[x]!=c) ++x;
if(x==a.size()) ba|=1; else ++x;
while(y<b.size()&&b[y]!=c) ++y;
if(y==b.size()) ba|=2; else ++y;
}
if(ba!=3) s.quitf(_wa,"subseq req not filled");
于是不难想到
但是这样做是
因为答案串长度是比较小的,大概是
转移时,记录对于每个位置,它后面每个字符出现的第一个位置,边界设
#include <bits/stdc++.h>
using namespace std;
const int N = 5010, inf = -0x3f3f3f3f;
int n, m;
string a, b;
struct sb
{
int j, pre, lst_ch;
} f[N][N];
int nxt[N][26][2];
sb Max(sb a, sb b)
{
if (a.j < b.j) return b;
else return a;
}
int main()
{
freopen("string.in", "r", stdin);
freopen("string.out", "w", stdout);
int T;
cin >> T;
while (T -- )
{
cin >> a >> b;
n = a.size(), m = b.size();
a = " " + a, b = " " + b;
for (int i = 0; i < 26; i ++ )
nxt[n + 1][i][0] = n + 1, nxt[n + 2][i][0] = n + 1,
nxt[m + 1][i][1] = m + 1, nxt[m + 2][i][1] = m + 1;
for (int i = n; i; i -- )
{
for (int j = 0; j < 26; j ++ )
nxt[i][j][0] = nxt[i + 1][j][0];
nxt[i][a[i] - 'a'][0] = i;
}
for (int i = m; i; i -- )
{
for (int j = 0; j < 26; j ++ )
nxt[i][j][1] = nxt[i + 1][j][1];
nxt[i][b[i] - 'a'][1] = i;
}
int lx = max(n, m) / 13 + 1;
for (int i = 0; i <= n + 1; i ++ )
for (int j = 0; j <= lx; j ++ )
f[i][j] = {inf, -1, 0};
for (int i = 0; i <= lx; i ++ )
f[0][i].j = 0;
for (int i = 0; i <= n; i ++ )
for (int j = 0; j <= lx; j ++ )
{
if (f[i][j].j == inf) continue;
for (int k = 0; k < 26; k ++ )
f[nxt[i + 1][k][0]][j + 1] = Max(f[nxt[i + 1][k][0]][j + 1], {nxt[f[i][j].j + 1][k][1], i, k});
}
int k = 0;
for (int j = 0; j <= lx; j ++ )
if (f[n + 1][j].j == m + 1)
{
k = j;
break;
}
// cout << k << '\n';
stack<char> stk;
int tmp = n + 1;
while (tmp)
{
stk.push(f[tmp][k].lst_ch + 'a');
tmp = f[tmp][k].pre;
k -- ;
}
while (stk.size()) cout << stk.top(), stk.pop();
cout << '\n';
}
return 0;
}
一直在想
设
然后转移先不考虑抽出的装载,只考虑在原序列中的装载,抽出的到最后再计算。
则
最后答案在
注意到会
#include <bits/stdc++.h>
#define inf 0x3f3f3f3f
#define need(x) (bool)x.flow + x.cnt_car
#define sum(x) x.cnt_car * w + x.flow
using namespace std;
const int N = 410;
int n, w;
int a[N], sum1[N], sum2[N];
struct sb
{
int cnt_car, flow;
} f[2][N][N];
sb operator + (sb a, int b)
{
return {a.flow + b >= w ? a.cnt_car + 1 : a.cnt_car, a.flow + b == w ? 0 : a.flow + b > w ? b : a.flow + b};
}
sb mn(sb a, sb b)
{
return a.cnt_car >= inf ? b : b.cnt_car >= inf ? a : sum(a) > sum(b) ? b : a;
}
int main()
{
freopen("pack.in", "r", stdin);
freopen("pack.out", "w", stdout);
cin >> n >> w;
for (int i = 1; i <= n; i ++ ) cin >> a[i];
for (int i = 1; i <= n; i ++ )
sum1[i] = sum1[i - 1] + (a[i] == 1),
sum2[i] = sum2[i - 1] + (a[i] == 2);
// for (int i = 1; i <= n; i ++ ) cout << sum1[i] << ' ' << sum2[i] << '\n';
memset(f, 0x3f, sizeof f);
f[0][0][0] = {0, 0};
for (int i = 1; i <= n; i ++ )
{
for (int x = 0; x <= sum1[i]; x ++ )
for (int y = 0; y <= sum2[i]; y ++ )
{
f[i & 1][x][y] = {inf, inf};
if (x && a[i] == 1) f[i & 1][x][y] = mn(f[i & 1][x][y], f[(i - 1) & 1][x - 1][y]);
if (y && a[i] == 2) f[i & 1][x][y] = mn(f[i & 1][x][y], f[(i - 1) & 1][x][y - 1]);
f[i & 1][x][y] = mn(f[i & 1][x][y], f[(i - 1) & 1][x][y] + a[i]);
// cout << (f[(i - 1) & 1][x][y] + a[i]).cnt_car << '\n';
}
}
// cout << inf * 10 << '\n';
// for (int x = 0; x <= sum1[n]; x ++ )
// for (int y = 0; y <= sum2[n]; y ++ )
// cout << f[n & 1][x][y].cnt_car*w+f[n&1][x][y].flow << "\n"[y != sum2[n]];
int res = inf, mi = inf;
for (int x = 0; x <= sum1[n]; x ++ )
for (int y = 0; y <= sum2[n]; y ++ )
{
auto tmp = f[n & 1][x][y];
// cout << tmp.cnt_car << ' ' << tmp.flow << '\n';
int tx = x, ty = y;
while (tx || ty)
{
if (tx && (!ty || tmp.flow + 2 > w)) tx -- , tmp = tmp + 1;
else ty -- , tmp = tmp + 2;
}
// cout << tmp.cnt_car << ' ' << tmp.flow << '\n';
// cout << need(tmp) << '\n';
if (mi > need(tmp))
{
mi = need(tmp);
res = x + y;
}
else if (mi == need(tmp)) res = min(res, x + y);
}
cout << res << '\n';
return 0;
}
考虑一个特殊性质:每段
不难想到直接从大到小放即可,然后在每段后面加入
将
不难发现,直接在每段中按整个序列的开头,进行正负交错放是可行的。
#include <bits/stdc++.h>
using namespace std;
const int N = 100010;
int n, a[N];
string s;
char ch[2] = {'L', 'R'};
pair<int, char> ch1[N];
map<char, int> mp = {{'L', 0}, {'R', 1}};
vector<pair<int, char> > pos;
bool cmp(int a, int b)
{
return a > b;
}
int main()
{
freopen("weight.in", "r", stdin);
freopen("weight.out", "w", stdout);
cin >> n;
for (int i = 1; i <= n; i ++ ) cin >> a[i];
cin >> s;
int num = 0;
s = " " + s;
for (int i = 1; i <= n; i ++ )
if (s[i] != s[i - 1])
{
num ++ ;
pos.push_back({i, s[i]});
}
sort(a + 1, a + 1 + n, cmp);
int num1 = num;
for (int i = 0; i < pos.size(); i ++ ) ch1[pos[i].first] = {a[num1 -- ], pos[i].second};
pos.push_back({n + 1, 'a'});
int tmp = 0;
cout << ch1[pos[0].first].first << ' ' << ch1[pos[0].first].second << '\n';
// cout << pos[0].second << ' ';
for (int i = 1; i < (int)pos.size(); i ++ )
{
int lst = pos[i - 1].first, nw = pos[i].first;
for (int j = lst + 1; j < nw; j ++ )
tmp ^= 1, cout << a[ ++ num] << ' ' << ch[(mp[pos[0].second] + tmp) & 1] << '\n';
// cout << pos[i].second << '\n';
if (i != pos.size() - 1) cout << ch1[pos[i].first].first << ' ' << ch1[pos[i].first].second << '\n';
}
return 0;
}
考虑根号分治,设置一个阈值
#include <bits/stdc++.h>
#define int long long
#define lowbit(i) (i & -i)
using namespace std;
const int N = 400010;
int n;
int a[N], b[N];
map<int, int> mp;
int tr[N];
bool st[N];
int cnt, num[N], sum[N];
void add(int x, int v)
{
for (int i = x; i <= n * 2; i += lowbit(i)) tr[i] += v;
}
int query(int x)
{
int res = 0;
for (int i = x; i; i -= lowbit(i)) res += tr[i];
return res;
}
signed main()
{
freopen("sequence.in", "r", stdin);
freopen("sequence.out", "w", stdout);
cin >> n;
for (int i = 1; i <= n; i ++ ) scanf("%lld", a + i);
int t = sqrt(n) * 2, res = 0;
for (int i = 1; i <= n; i ++ ) b[i] = a[i];
sort(b + 1, b + n + 1);
for (int i = 1; i <= n; i ++ )
if (!mp.count(b[i])) mp[b[i]] = ++ cnt;
for (int i = 1; i <= n; i ++ )
a[i] = mp[a[i]], num[a[i]] ++ ;
for (int i = 1; i <= cnt; i ++ )
{
if (num[i] <= t) continue;
add(n + 1, 1);
st[i] = 1;
for (int j = 1; j <= n; j ++ ) sum[j] = 0;
for (int j = 1; j <= n; j ++ )
{
sum[j] = sum[j - 1] + (bool)(a[j] == i);
res += query(sum[j] * 2 - j + n);
add(sum[j] * 2 - j + n + 1, 1);
}
add(n + 1, -1);
for (int j = 1; j <= n; j ++ )
add(sum[j] * 2 - j + n + 1, -1);
}
// cout << res << '\n';
for (int i = 1; i <= n; i ++ ) num[i] = 0;
for (int i = 1; i <= n; i ++ )
{
int mx = 0, col = 0;
for (int j = i; j <= min(n, i + 2 * t - 1); j ++ )
{
num[a[j]] ++ ;
if (num[a[j]] > mx)
{
mx = num[a[j]];
col = a[j];
}
if (j - i + 1 < 2 * mx && !st[col]) res ++ ;
}
for (int j = i; j <= i + 2 * t - 1; j ++ )
num[a[j]] = 0;
}
cout << res << '\n';
return 0;
}
本文来自博客园,作者:爱朝比奈まふゆ的MafuyuQWQ。 转载请注明原文链接:https://www.cnblogs.com/MafuyuQWQ/p/18417083
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· Deepseek官网太卡,教你白嫖阿里云的Deepseek-R1满血版
· 2分钟学会 DeepSeek API,竟然比官方更好用!
· .NET 使用 DeepSeek R1 开发智能 AI 客户端
· DeepSeek本地性能调优
· 一文掌握DeepSeek本地部署+Page Assist浏览器插件+C#接口调用+局域网访问!全攻略