220906 总结

220906 总结

时间有点短,做到后面稍微有点慌

怎么就想不到应该用什么算法呢。。。

赛时估计:100+30+0

赛后测试:100+30+0

赛后一看,还真没难题

T1 购物

直接模拟即可

T2 第 k 小

想的是将所有区间排序,顺着区间统计数量,该区间结束就在下一个区间的这个位置接着跑

但是值域 2×109 跑不过啊 /youl

做的时候一直在想怎么缩小值域去统计结果(

最后打了个暴力就跑路了

应该但没意识到这个答案具有二分性质,即小于第 k 小的数都比第 k 小的数小(什么废话

但是一看题解就发现了。。。呜

x 表示第 k 小的数,二分 x

check 的时候扫一遍所有区间统计小于等于 x 的数的个数 s

如果 sK 则表示 x 取大了

#include<bits/stdc++.h>
using namespace std;
const int maxN = 1e5;
struct Segment {
int l, r;
friend bool operator < (Segment A, Segment B) {
if (A.l != B.l) return A.l < B.l;
return A.r > B.r;
}
} A[maxN];
int N, K;
bool check(int k) {
int cnt = 0;
for (int i = 1; i <= N; i++) {
if (A[i].l <= k) cnt += min(k, A[i].r) - A[i].l + 1;
}
return cnt >= K;
}
int main() {
freopen("thekth.in", "r", stdin);
freopen("thekth.out", "w", stdout);
scanf("%d", &N);
for (int i = 1; i <= N; i++) {
int l, r;
scanf("%d%d", &A[i].l, &A[i].r);
}
scanf("%d", &K);
int l = -1e9;
int r = 1e9;
int ans = 0;
while (l <= r) {
int mid = (l + r) >> 1;
if (check(mid)) {
ans = mid;
r = mid - 1;
} else l = mid + 1;
}
printf("%d", ans);
return 0;
}

T3 最大半连通子图

考的时候在要不要略过 T2 之间摇摆不定导致只剩半小时写这道题了...寄!

半小时糊了一个实际上思路正确但被我写挂了的TLE做法

将所有的 scc 缩成一个点,那么最大半联通子图实际上就是找缩完点形成的这张 DAG 上的最长链

使用拓扑排序更新最长链的长度,如果成功更新,那么重置长度最大值及个数;如果当前长度与最长链长度相同,则更新最长链个数。

Lg 上这么就能过了,但是 Lemon 测的时候还得卡卡常才能过(

#include<bits/stdc++.h>
using namespace std;
const int maxN = 1e5 + 10;
int MOD;
vector<int> G[maxN];
int N, M;
stack<int>s;
int ins[maxN];
int dfn[maxN];
int low[maxN];
int cnt = 0;
int sccNum = 0;
int sccSiz[maxN];
int scc[maxN];
void tarjan(int u) {
cnt++;
dfn[u] = cnt;
low[u] = cnt;
s.push(u);
ins[u] = 1;
for (auto i : G[u]) {
int v = i;
if (!dfn[v]) {
tarjan(v);
low[u] = min(low[u], low[v]);
} else if (ins[v]) {
low[u] = min(low[u], dfn[v]);
}
}
if (low[u] == dfn[u]) {
ins[u] = 0;
sccNum++;
scc[u] = sccNum;
sccSiz[sccNum] = 1;
while (s.top() != u) {
int sT = s.top();
scc[sT] = sccNum;
ins[sT] = 0;
sccSiz[sccNum]++;
s.pop();
}
s.pop();
}
return;
}
vector<int> G2[maxN];
int inD[maxN];
inline void reBuid() {
unordered_set<long long> S;
for (int i = 1; i <= N; i++) {
for (auto j : G[i]) {
long long H = 100000ll * scc[i] + scc[j];
if (S.count(H)) continue;
if (scc[i] != scc[j]) {
G2[scc[i]].push_back(scc[j]);
inD[scc[j]]++;
}
S.insert(H);
}
}
}
int dp[maxN];
int num[maxN];
inline void Topo() {
queue<int> Q;
for (int i = 1 ; i <= sccNum; i++) {
if (inD[i] == 0) Q.push(i);
dp[i] = sccSiz[i];
num[i] = 1;
}
while (!Q.empty()) {
int u = Q.front();
Q.pop();
for (auto i : G2[u]) {
if (dp[i] < dp[u] + sccSiz[i]) {
dp[i] = dp[u] + sccSiz[i];
num[i] = num[u];
} else if (dp[i] == dp[u] + sccSiz[i]) {
num[i] = (num[u] % MOD + num[i] % MOD) % MOD;
}
if (--inD[i] == 0) Q.push(i);
}
}
}
int main() {
ios :: sync_with_stdio(false);
freopen("semi.in", "r", stdin);
freopen("semi.out", "w", stdout);
cin >> N >> M >> MOD;
for (int i = 1; i <= M; i++) {
int u, v;
cin >> u >> v;
G[u].push_back(v);
}
for (int i = 1; i <= N; i++) if (!dfn[i]) tarjan(i);
reBuid();
Topo();
int dis = -1;
int ans = -1;
for (int i = 1; i <= sccNum; i++) {
if (dp[i] > dis) {
dis = dp[i];
ans = num[i];
} else if (dp[i] == dis) {
ans = (ans % MOD + num[i] % MOD) % MOD;
}
}
printf("%d\n%d", dis, ans);
return 0;
}

简单总结

  • 稳一点

  • 觉得算法不行的时候考虑考虑题目具有的性质

  • 别急,急也没用.jpg

  • 码力不太够,表现在代码细节出现令人智熄的离谱错误

posted @   Burnling  阅读(48)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库
点击右上角即可分享
微信分享提示