C - Minimum Value Rectangle
题意:给n根木棒,选4根组成长方形,使得这个长方形的周长的平方比上其面积最小。
题解:对那个式子求导,发现对于同一个长来说,是长和宽越接近,上式越小。那么排序之后每个和他附近的一个组装一下就行了。
map<int, int> m;
vector<int> v;
void test_case() {
int n;
scanf("%d", &n);
m.clear();
for(int i = 1; i <= n; ++i) {
int ai;
scanf("%d", &ai);
m[ai]++;
}
v.clear();
for(auto &j : m) {
if(j.second == 2 || j.second == 3)
v.push_back(j.first);
else if(j.second >= 4) {
printf("%d %d %d %d\n", j.first, j.first, j.first, j.first);
return;
}
}
ll fz, fm, a, b;
n = v.size();
for(int i = 0; i < n - 1; ++i) {
ll nfz = 2ll * (v[i] + v[i + 1]);
nfz *= nfz;
ll nfm = 1ll * v[i] * v[i + 1];
if(i == 0 || nfz * fm < fz * nfm) {
a = v[i];
b = v[i + 1];
fz = nfz;
fm = nfm;
}
}
printf("%lld %lld %lld %lld\n", a, a, b, b);
}
事实上可能不需要map,直接来一波快排,然后跑一遍nxt。
int a[1000005];
int b[1000005];
void test_case() {
int n;
scanf("%d", &n);
for(int i = 1; i <= n; ++i)
scanf("%d", &a[i]);
sort(a + 1, a + 1 + n);
int w, h, btop = 0;
for(int i = 1, nxt; i <= n; i = nxt) {
for(nxt = i + 1; nxt <= n && a[nxt] == a[i]; ++nxt);
int cnt = nxt - i;
if(cnt >= 4) {
printf("%d %d %d %d\n", a[i], a[i], a[i], a[i]);
return;
}
if(cnt >= 2)
b[++btop] = a[i];
}
ll fz, fm;
for(int i = 1; i < btop; ++i) {
ll nfz = 2ll * (b[i] + b[i + 1]);
nfz *= nfz;
ll nfm = 1ll * b[i] * b[i + 1];
if(i == 1 || nfz * fm < fz * nfm) {
w = b[i];
h = b[i + 1];
fz = nfz;
fm = nfm;
}
}
printf("%d %d %d %d\n", w, w, h, h);
}
D - Mouse Hunt
题意:有n个房间,有1个老鼠,开始可能在任意一个房间,在第i个房间放陷阱花ci,老鼠在第i个房间下一次就会到ai。求最便宜的陷阱总额。
题解:基环树的内向树。乱搞一点直接套Kosaraju缩点,然后缩点之后的代表点放这堆点的最小值,然后把所有0出度的ci加起来。
不过这个跟反图没有任何关系,加边然后去重甚至都不需要加边和去重直接统计出度(因为0始终是0,非0的出度去重后出度也不会是0)。
namespace SCC {
const int MAXN = 2e5;
int n;
vector<int> G[MAXN + 5], BG[MAXN + 5];
int c1[MAXN + 5], cntc1;
int c2[MAXN + 5], cntc2;
int s[MAXN + 5], cnts;
int n2;
vector<int> V2[MAXN + 5];
//vector<int> G2[MAXN + 5], BG2[MAXN + 5];
const int INF = 0x3f3f3f3f;
int C1[MAXN + 5], C2[MAXN + 5];
void Init(int _n) {
n = _n;
cntc1 = 0, cntc2 = 0, cnts = 0;
for(int i = 1; i <= n; ++i) {
G[i].clear();
BG[i].clear();
c1[i] = 0;
c2[i] = 0;
s[i] = 0;
V2[i].clear();
//G2[i].clear();
//BG2[i].clear();
C2[i] = INF;
}
for(int i = 1; i <= n; ++i)
scanf("%d", &C1[i]);
for(int i = 1, v; i <= n; ++i) {
scanf("%d", &v);
G[i].push_back(v);
BG[v].push_back(i);
}
}
/*void AddEdge(int u, int v) {
G[u].push_back(v);
BG[v].push_back(u);
}*/
void dfs1(int u) {
c1[u] = cntc1;
for(int v : G[u]) {
if(!c1[v])
dfs1(v);
}
s[++cnts] = u;
}
void dfs2(int u) {
V2[cntc2].push_back(u);
C2[cntc2] = min(C2[cntc2], C1[u]);
c2[u] = cntc2;
for(int v : BG[u]) {
if(!c2[v])
dfs2(v);
}
}
void Kosaraju() {
for(int i = 1; i <= n; ++i) {
if(!c1[i]) {
++cntc1;
dfs1(i);
}
}
for(int i = n; i >= 1; --i) {
if(!c2[s[i]]) {
++cntc2;
dfs2(s[i]);
}
}
}
/*void Build() {
n2 = cntc2;
for(int i = 1; i <= n2; ++i) {
for(auto u : V2[i]) {
for(auto v : G[u]) {
if(c2[v] != i) {
G2[i].push_back(c2[v]);
BG2[c2[v]].push_back(i);
}
}
}
}
for(int i = 1; i <= n2; ++i) {
sort(G2[i].begin(), G2[i].end());
G2[i].erase(unique(G2[i].begin(), G2[i].end()), G2[i].end());
sort(BG2[i].begin(), BG2[i].end());
BG2[i].erase(unique(BG2[i].begin(), BG2[i].end()), BG2[i].end());
}
}*/
void Solve() {
ll ans = 0;
n2 = cntc2;
for(int i = 1; i <= n2; ++i) {
bool cnt = 0;
for(auto u : V2[i]) {
for(auto v : G[u]) {
if(c2[v] != i) {
cnt = 1;
break;
}
}
if(cnt)
break;
}
if(!cnt)
ans += C2[i];
}
printf("%lld\n", ans);
}
}
void test_case() {
int n;
scanf("%d", &n);
SCC::Init(n);
SCC::Kosaraju();
SCC::Solve();
}
要是真按基环树去做,是不是要从入度0的点一个一个dfs下去找环,然后有环回溯的时候顺带找一波最小值?老套路用个全局变量记录重复点的id,直到回溯到它都标记为环。注意dfs的时候要染色,遇到其他颜色dfs过的就直接退出。不过我这不是有现成的缩点模板吗?
原文地址:https://www.cnblogs.com/KisekiPurin2019/p/11979991.html
时间: 2024-11-09 12:47:28