CSP-S模拟16 (没有T3和T4)
不及时放代码是因为我懒,想最后再使用Markdown,它太麻烦了!
“你的朝六晚十,你的书山题海,一定一定,都是值得……”
A. 猜道路
我在干嘛?!一个Floyed就能解决的事情我先建了一个最小生成树再往上添边,每次对新添的两个点跑dij再用这个值去更新别的点,直接整了158行?!(想必是昨天的T2造成了心理阴影……)
Floyed
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 303;
const int N = 9e4 + 3;
const int inf = 0x3f3f3f3f;
int n, mp[maxn][maxn];
bool del[maxn][maxn];
inline int read()
{
int x = 0, f = 1;
char ch = getchar();
while(ch < '0' || ch > '9')
{
if(ch == '-')
{
f = -1;
}
ch = getchar();
}
while(ch >= '0' && ch <= '9')
{
x = (x << 1) + (x << 3) + (ch^48);
ch = getchar();
}
return x * f;
}
int main()
{
n = read();
for(int i=1; i<=n; i++)
{
for(int j=1; j<=n; j++)
{
mp[i][j] = read();
}
}
bool fl = 1;
for(int k=1; k<=n && fl; k++)
{
for(int i=1; i<=n && fl; i++)
{
for(int j=1; j<=n; j++)
{
if(i!=k && i!=j && j!=k)
{
if(mp[i][k]+mp[k][j]<mp[i][j])
{
fl = 0; break;
}
if(mp[i][k]+mp[k][j]==mp[i][j]) del[i][j] = del[j][i] = 1;
}
}
}
}
if(fl)
{
ll ans = 0;
for(int i=1; i<=n; i++)
{
for(int j=1; j<i; j++)
{
if(!del[i][j]) ans += mp[i][j];
}
}
printf("%lld\n", ans);
}
else printf("-1\n");
return 0;
}
Mine
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 303;
const int N = 9e4 + 3;
const int inf = 0x3f3f3f3f;
int e[maxn][maxn], n, fa[maxn], cnt;
ll ans, dis[maxn][maxn];
bool ext[N], vis[maxn];
typedef pair<ll, int> paint;
inline int read()
{
int x = 0, f = 1;
char ch = getchar();
while(ch < '0' || ch > '9')
{
if(ch == '-')
{
f = -1;
}
ch = getchar();
}
while(ch >= '0' && ch <= '9')
{
x = (x << 1) + (x << 3) + (ch^48);
ch = getchar();
}
return x * f;
}
struct node
{
int next, to, w;
}a[N];
int head[maxn], len;
void add(int x, int y, int w)
{
a[++len].to = y; a[len].next = head[x]; a[len].w = w;
head[x] = len;
}
struct edge
{
int u, v, w;
bool operator < (const edge &T) const
{
return w < T.w;
}
}s[N];
int find(int x)
{
if(x == fa[x]) return x;
return fa[x] = find(fa[x]);
}
void un(int x, int y) {fa[find(x)] = find(y);}
priority_queue<paint, vector<paint>, greater<paint> > q;
void dij(int st, ll dis[])
{
for(int i=1; i<=n; i++) vis[i] = 0;
dis[st] = 0;
q.push(make_pair(dis[st], st));
while(!q.empty())
{
int x = q.top().second; q.pop();
if(vis[x]) continue;
for(int i=head[x]; i; i=a[i].next)
{
int v = a[i].to;
if(dis[v] > dis[x] + a[i].w)
{
dis[v] = dis[x] + a[i].w;
q.push(make_pair(dis[v], v));
}
}
}
}
int main()
{
n = read();
for(int i=1; i<=n; i++)
{
for(int j=1; j<=n; j++)
{
e[i][j] = read();
}
}
for(int i=1; i<n; i++)
{
for(int j=i+1; j<=n; j++)
{
s[++cnt] = {i, j, e[i][j]};
}
}
sort(s+1, s+1+cnt);
for(int i=1; i<=n; i++) fa[i] = i;
int tot = 0;
for(int i=1; i<=cnt; i++)
{
if(find(s[i].u) != find(s[i].v))
{
add(s[i].u, s[i].v, s[i].w); add(s[i].v, s[i].u, s[i].w);
un(s[i].u, s[i].v);
tot++; ext[i] = 1;
ans += s[i].w;
//printf("add:(%d, %d, %d)\n", s[i].u, s[i].v, s[i].w);
}
if(tot == n-1) {break;}
}
memset(dis, 0x3f, sizeof(dis));
for(int i=1; i<=n; i++) dij(i, dis[i]);
/*for(int i=1; i<=n; i++)
{
for(int j=1; j<=n; j++) printf("dis[%d][%d] = %lld\n", i, j, dis[i][j]);
printf("\n");
}*/
for(int i=1; i<=cnt; i++)
{
if(ext[i] || s[i].w == dis[s[i].u][s[i].v]) continue;
//printf("cmp : %d %lld\n", s[i].w, dis[s[i].u][s[i].v]);
if(s[i].w > dis[s[i].u][s[i].v])
{
printf("-1"); exit(0);
}
else
{
ans += s[i].w;
//printf("add:(%d, %d, %d)\n", s[i].u, s[i].v, s[i].w);
add(s[i].u, s[i].v, s[i].w); add(s[i].v, s[i].u, s[i].w);
dij(s[i].u, dis[s[i].u]); dij(s[i].v, dis[s[i].v]);
for(int j=1; j<=n; j++)
{
for(int k=1; k<=n; k++)
{
if(dis[s[i].u][j]+dis[s[i].u][k] < dis[j][k])
{
dis[j][k] = dis[s[i].u][j]+dis[s[i].u][k];
}
if(dis[s[i].v][j]+dis[s[i].v][k] < dis[j][k])
{
dis[j][k] = dis[s[i].v][j]+dis[s[i].v][k];
}
}
}
}
}
printf("%lld\n", ans);
return 0;
}
B. 简单环
输出0就有60,同样是乱搞,我乱搞的方式就比较Sily……
先建了一棵搜索树,然后打算判断一下每个点只有一条返祖边,1没考虑到不一定相同起点只要覆盖次数超了就不行,2不会实现以上操作,最后打算把所有返祖边塞进去都输出,WA 11***
鹤题解去了,%%%Delov / lxhcr,才知道树上差分可以当场求子树和(权值),我只会事后再加---应用:暗之链锁(A层邀请赛4)---关于树上路径覆盖的套路居然没有想到树上差分,zzz
积累一个函数:minmax(a, b) 返回一个pair,其中first是较小值,second是较大值。
code
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 1e5 + 4;
const int N = 2e5 + 4;
const int inf = 0x3f3f3f3f;
int fa[maxn], dep[maxn], val[maxn], pre[maxn], n, m;
bool vis[maxn];
vector<int> ans, son[maxn], gr[maxn];
typedef pair<int, int> paint;
map<paint, int> Map;
inline int read()
{
int x = 0, f = 1;
char ch = getchar();
while(ch < '0' || ch > '9')
{
if(ch == '-')
{
f = -1;
}
ch = getchar();
}
while(ch >= '0' && ch <= '9')
{
x = (x << 1) + (x << 3) + (ch^48);
ch = getchar();
}
return x * f;
}
struct node
{
int next, to;
}a[N];
int head[maxn], len;
void add(int x, int y)
{
a[++len].to = y; a[len].next = head[x];
head[x] = len;
}
void dfs1(int u, int f)
{
vis[u] = 1;
dep[u] = dep[f] + 1;
for(int i=head[u]; i; i=a[i].next)
{
int v = a[i].to;
if(v == f) continue;
if(!vis[v])
{
dfs1(v, u); val[u] += val[v]; son[u].push_back(v); fa[v] = u;
}
else if(dep[v] < dep[u])
{
val[u]++; val[v]--; gr[u].push_back(v);
}
}
}
void dfs2(int u)
{
pre[u] = (val[u]==1) + pre[fa[u]];
for(int v : gr[u]) if(pre[v]-pre[u] == dep[v]-dep[u])
{
ans.push_back(Map[minmax(u, v)]);
int now = u, pt = fa[u];
while(now != v) {ans.push_back(Map[minmax(now, pt)]); now = pt; pt = fa[now];}
}
for(int v : son[u]) dfs2(v);
}
int main()
{
n = read(); m = read();
for(int i=1; i<=m; i++)
{
int u = read(), v = read();
add(u, v); add(v, u);
Map[minmax(u, v)] = i;
}
for(int i=1; i<=n; i++)
{
if(!vis[i])
{
dfs1(i, 0); dfs2(i);
}
}
int sz = ans.size();
printf("%d\n", sz);
sort(ans.begin(), ans.end());
for(int i=0; i<sz; i++)
{
printf("%d ", ans[i]);
}
return 0;
}
C. 汉明距离
直接暴力75 pts 多项式什么的,emmm……我……我居然又咕了一个题……
D. 勇者的后缀
56 pts之后的所有点都MLE了,可持久化Trie都没炸内存**实测sring的函数真是yyds
幸好string可以sort,否则我发现我不知道字典序大小的比较规则了***zzz
1.字符串左对齐比较 2.字母无大小写对应关系时忽略大小写,‘B’ > 'A' 和 'a' 3.字母有大小写对应关系时,大写小于小写,比如 'A' < 'a' 4.前缀相等较长的更小(空格小于所有字符)
所以这题就是个LCP的板子?!
即使是板子它照样很鬼畜,本来打算鹤的,又不想鹤了***
时光花火,水月星辰