2023冲刺国赛自测5
怎么都能切题啊、、
怎么就我是个暴力老哥啊。。。。
这样下去国赛岂不是打铁了。。。。。。。。。
A. 今晚九点
从一个点向其一步走到的位置连边,权值为 , 向相邻的点连边,权值为
跑最短路就是答案。
code
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int, int> pii;
int read(){
int x = 0; char c = getchar();
while(!isdigit(c))c = getchar();
do{x = x * 10 + (c ^ 48); c = getchar();}while(isdigit(c));
return x;
}
const int maxn = 1005;
int n, m;
int id(int i, int j){return (i - 1) * m + j;}
char s[maxn][maxn];
int head[maxn * maxn], tot;
struct edge{int to, net, val;}e[maxn * maxn * 8];
void add(int u, int v, int w){
e[++tot] = {v, head[u], w};
head[u] = tot;
}
int pre[maxn];
int dis[maxn * maxn];
bool vis[maxn * maxn];
priority_queue<pii, vector<pii>, greater<pii>>q;
int main(){
freopen("a.in","r",stdin);
freopen("a.out","w",stdout);
n = read(), m = read();
for(int i = 1; i <= n; ++i)scanf("%s",s[i] + 1);
for(int i = 1; i <= n; ++i){
for(int j = 1; j <= m; ++j)
if(s[i][j] == '#')pre[j] = 0;
else{
if(i == 1 || s[i - 1][j] == '#')pre[j] = i;
else if(pre[j])add(id(i, j), id(pre[j], j), 1);
}
}
for(int i = 1; i <= m; ++i)pre[i] = 0;
for(int i = n; i >= 1; --i){
for(int j = 1; j <= m; ++j)
if(s[i][j] == '#')pre[j] = 0;
else{
if(i == n || s[i + 1][j] == '#')pre[j] = i;
else if(pre[j])add(id(i, j), id(pre[j], j), 1);
}
}
for(int i = 1; i <= n; ++i){
int pre = 0;
for(int j = 1; j <= m; ++j)
if(s[i][j] == '#')pre = 0;
else{
if(j == 1 || s[i][j - 1] == '#')pre = j;
else if(pre)add(id(i, j), id(i, pre), 1);
}
pre = 0;
for(int j = m; j >= 1; --j)
if(s[i][j] == '#')pre = 0;
else{
if(j == m || s[i][j + 1] == '#')pre = j;
else if(pre)add(id(i, j), id(i, pre), 1);
}
}
for(int i = 1; i <= n; ++i)
for(int j = 1; j <= m; ++j)
if(s[i][j] == '.'){
if(s[i - 1][j] == '.')add(id(i, j), id(i - 1, j), 2);
if(s[i + 1][j] == '.')add(id(i, j), id(i + 1, j), 2);
if(s[i][j + 1] == '.')add(id(i, j), id(i, j + 1), 2);
if(s[i][j - 1] == '.')add(id(i, j), id(i, j - 1), 2);
}
int a = read(), b = read(), c = read(), d = read();
int des = id(c, d);
memset(dis, 0x3f, sizeof(dis));
dis[id(a, b)] = 0; q.push(pii(0, id(a, b)));
while(!q.empty()){
int x = q.top().second; q.pop();
if(vis[x])continue;
vis[x] = true;
if(x == des)break;
for(int i = head[x]; i; i = e[i].net){
int v = e[i].to;
if(dis[v] > dis[x] + e[i].val){
dis[v] = dis[x] + e[i].val;
q.push(pii(dis[v], v));
}
}
}
printf("%d\n",dis[des] == 0x3f3f3f3f ? -1 : dis[des]);
return 0;
}
B. 小王唱歌
我咋这么菜,但凡是个数据结构就不会写+调半年。
哦,我是啥都不会,啥都得调半年啊,nmsl。
表示 选择颜色 其子树内方案数
转移为
值域显然可以离散化。
考虑如何优化这个过程。
的值为连续段,那么可以用珂朵莉树的思想进行维护
加上启发式合并,发现复杂度是 的,可以接受
实现起来细节挺多的吧?但是 说直接无脑写就行。
还是我太菜了。
你需要实现区间加法乘法求和,用来快速把 变成
然后因为 不同,你需要把儿子强制对齐成父亲的长度
其实都是常规?操作
code
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int, int> pii;
int read(){
int x = 0; char c = getchar();
while(!isdigit(c))c = getchar();
do{x = x * 10 + (c ^ 48); c = getchar();}while(isdigit(c));
return x;
}
const int mod = 998244353, maxn = 5e5 + 55;
mt19937 rd(0);
int sint(){return rd();}
int n, m, a[maxn], b[maxn];
vector<int>g[maxn];
struct FHQ{
struct node{
int sum, multag, addtag, len, si, l, r, val, f, key, slen;
}t[maxn * 2];
int cnt = 0;
int bin[maxn * 2], tp;
int Nid(){if(tp)return bin[tp--]; return ++cnt;}
int New(int val, int len, int f){
int ct = Nid();
t[ct] = {(int)(1ll * len * f % mod), 1, 0, len, 1, 0, 0, val, f, sint(), len};
return ct;
}
void push_up(int x){
t[x].sum = (t[t[x].l].sum + t[t[x].r].sum + 1ll * t[x].f * t[x].len) % mod;
t[x].si = t[t[x].l].si + t[t[x].r].si + 1;
t[x].slen = t[t[x].l].slen + t[t[x].r].slen + t[x].len;
}
void mul(int x, int v){
t[x].addtag = 1ll * t[x].addtag * v % mod;
t[x].f = 1ll * t[x].f * v % mod;
t[x].multag = 1ll * t[x].multag * v % mod;
t[x].sum = 1ll * t[x].sum * v % mod;
}
void add(int x, int v){
t[x].addtag = (t[x].addtag + v) % mod;
t[x].f = (t[x].f + v) % mod;
t[x].sum = (t[x].sum + 1ll * t[x].slen * v) % mod;
}
void push_down(int x){
if(t[x].multag != 1){
if(t[x].l)mul(t[x].l, t[x].multag);
if(t[x].r)mul(t[x].r, t[x].multag);
t[x].multag = 1;
}
if(t[x].addtag){
if(t[x].l)add(t[x].l, t[x].addtag);
if(t[x].r)add(t[x].r, t[x].addtag);
t[x].addtag = 0;
}
}
void split(int x, int k, int &l, int &r){
if(!x){l = r = 0;return;}
push_down(x);
if(t[x].val <= k){l = x; split(t[x].r, k, t[x].r, r); push_up(x);}
else{r = x; split(t[x].l, k, l, t[x].l); push_up(x);}
}
int merge(int x, int y){
if(!x || !y)return x | y;
if(t[x].key < t[y].key){
push_down(x); t[x].r = merge(t[x].r, y); push_up(x); return x;
}else{
push_down(y); t[y].l = merge(x, t[y].l); push_up(y); return y;
}
}
void get(int &rt, int x){rt = New(1, a[b[x]], 1);}
int st[maxn], top;
void dfs(int x){
push_down(x);
if(t[x].l)dfs(t[x].l);
st[++top] = x;
if(t[x].r)dfs(t[x].r);
}
vector<int>stk;
void mul(int &rt, int L, int R, int val){
int l = 0, r = 0, m = 0;
split(rt, L - 1, l, r);
split(r, R, m, r);
int x = m; while(t[x].r)stk.push_back(x), push_down(x), x = t[x].r; stk.push_back(x);
if(t[x].val + t[x].len - 1 > R){
r = merge(New(R + 1, t[x].len - (R - t[x].val + 1), t[x].f), r);
t[x].len = R - t[x].val + 1;
}
while(stk.size())push_up(stk.back()), stk.pop_back();
mul(m, val);
rt = merge(merge(l, m), r);
}
void change(int &rt, int R){
int sum = t[rt].sum;
int r = 0;
split(rt, R, rt, r);
int x = rt; while(t[x].r)stk.push_back(x), push_down(x), x = t[x].r; stk.push_back(x);
if(t[x].val + t[x].len - 1 < R)t[x].r = New(t[x].val + t[x].len, R - t[x].val - t[x].len + 1, 0);
else t[x].len = R - t[x].val + 1;
while(stk.size())push_up(stk.back()), stk.pop_back();
mul(rt, mod - 1); add(rt, sum);
top = 0; if(r)dfs(r); for(int i = 1; i <= top; ++i)bin[++tp] = st[i];
}
void merge_mul(int &rt1, int &rt2){
if(t[rt1].si < t[rt2].si)swap(rt1, rt2);
top = 0; dfs(rt2);
for(int i = 1; i <= top; ++i){
int l = t[st[i]].val, r = t[st[i]].val + t[st[i]].len - 1;
mul(rt1, l, r, t[st[i]].f);
}
for(int i = 1; i <= top; ++i)bin[++tp] = st[i];
}
}T;
int rt[maxn];
void solve(int x, int fa){
T.get(rt[x], x);
for(int v : g[x])if(v != fa){
solve(v, x);
T.change(rt[v], a[b[x]]);
T.merge_mul(rt[x], rt[v]);
}
}
int main(){
freopen("b.in","r",stdin);
freopen("b.out","w",stdout);
n = read(); for(int i = 1; i <= n; ++i)b[i] = a[i] = read();
sort(a + 1, a + n + 1); m = unique(a + 1, a + n + 1) - a - 1;
for(int i = 1; i <= n; ++i)b[i] = lower_bound(a + 1, a + m + 1, b[i]) - a;
for(int i = 1; i < n; ++i){
int u = read(), v = read();
g[u].push_back(v); g[v].push_back(u);
}
solve(1, 0);
printf("%d\n", T.t[rt[1]].sum);
return 0;
}
C. 不见不散
经典结论:交换序列上任意两数,逆序对数变化为奇数
那么逆序对数与 奇偶性不同的一定无解
否则一定有解
考虑某个人需要的东西如果在 手中,那么可以让他与每个人交换一次,最后与 交换,这样可以删去他得到一个子问题。
然后问题等价于特殊性质
由于上面的结论,有解的话点数一定是
那么可以 个点一起删去
删去的方法可以构造出来,详细见程序
code
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int, int> pii;
int read(){
int x = 0; char c = getchar();
while(!isdigit(c))c = getchar();
do{x = x * 10 + (c ^ 48); c = getchar();}while(isdigit(c));
return x;
}
const int maxn = 1005;
int n, a[maxn];
vector<pii>ans;
vector<int>s;
void swa(int x, int y){swap(a[x], a[y]); ans.push_back(pii(x, y));}
void solve(int x,int y){
for(int i : s)swa(x, i);
swa(x, y); reverse(s.begin(),s.end());
for(int i : s)swa(y, i);
}
void del4(){
int x = s.back(); s.pop_back();
int y = s.back(); s.pop_back();
int z = s.back(); s.pop_back();
int w = s.back(); s.pop_back();
solve(x, y); solve(z, w);
swa(x, z); swa(y, w); swa(x, w); swa(y, z);
}
void print(){
printf("YES\n");
for(pii v : ans)printf("%d %d\n", v.first, v.second);
}
int main(){
freopen("c.in","r",stdin);
freopen("c.out","w",stdout);
n = read(); for(int i = 1; i <= n; ++i)a[read()] = i;
for(int i = 1; i <= n; ++i)s.push_back(i);
for(int round = 1; round <= n; ++round){
int x = 0; for(int i : s)if(a[i] != i){x = i; break;}
if(!x)break;
int y; for(int i : s)if(a[i] == x){y = i; break;}
for(int i : s)if(i != x && i != y)swa(x, i);
swa(x, y);
for(int i = 0; i < s.size() - 1; ++i)if(s[i] == x)swap(s[i], s[i + 1]); s.pop_back();
}
while(s.size() > 3)del4();
if(s.size() > 1)printf("NO\n"); else print();
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】