2023.10.6解题报告
2023.10.6
20 + 40 + 0 = 60
T1
一开始想到了类似二分图的转化,但是没想出来怎么构造答案。
我们考虑将区间按左端点为第一关键字,右端点为第二关键字排序,用一个小根堆来维护当前在堆内的最小的右端点。
考虑扫一遍排好序的区间,如果当前点的左端点大于等于堆顶的右端点,就一直弹,直到最后堆空或者与当前区间相交。
因为排序是优先按照左端点排序,所以堆内的区间,左端点一定小于当前枚举到的左端点,要是右端点大于当前区间的左端点,那就是相交了。
我们按照堆内元素的情况来分:
-
当前堆内为空,那么当前的区间放哪边都可以,方案数乘 \(2\)。
-
当前堆内有一个,那么当前区间和堆内的元素绑定,方案数乘 \(1\)。
-
当前堆内有两个及以上,那么无解,输出 \(0\)。
复杂度近似 \(O(n)\)
/*
* @Author: Aisaka_Taiga
* @Date: 2023-10-06 14:25:22
* @LastEditTime: 2023-10-06 14:38:55
* @LastEditors: Aisaka_Taiga
* @FilePath: \Desktop\T1_100.cpp
* The heart is higher than the sky, and life is thinner than paper.
*/
#include<bits/stdc++.h>
#define int long long
#define P 998244353
#define N 1000100
using namespace std;
inline int read()
{
int x = 0, f = 1;
char c = getchar();
while(c < '0' || c > '9'){if(c == '-') f = -1; c = getchar();}
while(c <= '9' && c >= '0') x = (x << 1) + (x << 3) + (c ^ 48), c = getchar();
return x * f;
}
int n, ans;
struct node{int l, r;}e[N];
priority_queue<int, vector<int>, greater<int> > q;
inline int cmp(node a, node b){if(a.l == b.l) return a.r < b.r; return a.l < b.l;}
signed main()
{
n = read();
ans = 1;
for(int i = 1; i <= n; i ++) e[i] = (node){read(), read()};
sort(e + 1, e + n + 1, cmp);//按照左端点排序
for(int i = 1; i <= n; i ++)
{
while(!q.empty() && q.top() <= e[i].l) q.pop();//把不相交的都去掉
if(q.empty()) ans = ans * 2 % P;//空就代表没有与之相交的,放哪边都行
if(q.size() > 1) return cout << '0', 0;//大于1个相交的,没有方案
q.push(e[i].r);//将右端点放进去
}
cout << ans << endl;
return 0;
}
赛时暴力代码:
/*
* @Author: Aisaka_Taiga
* @Date: 2023-10-06 09:14:35
* @LastEditTime: 2023-10-06 09:22:03
* @LastEditors: Aisaka_Taiga
* @FilePath: \Desktop\T1.cpp
* The heart is higher than the sky, and life is thinner than paper.
*/
#include <bits/stdc++.h>
#define int long long
#define N 1000100
#define endl '\n'
using namespace std;
inline int read()
{
int x = 0, f = 1;
char c = getchar();
while(c < '0' || c > '9'){if(c == '-') f = -1; c = getchar();}
while(c <= '9' && c >= '0') x = (x << 1) + (x << 3) + (c ^ 48), c = getchar();
return x * f;
}
int n, ans, vis[N];
struct node{int l, r;}e[N];
inline int cmp(node a, node b)
{
if(a.l == b.l) return a.r < b.r;
return a.l < b.l;
}
inline void check()
{
int l1 = -1, l2 = -1;
for(int i = 1; i <= n; i ++)
{
if(vis[i] == 1){if(e[i].l < l1) return ; l1 = e[i].r;}
if(vis[i] == 0){if(e[i].l < l2) return ; l2 = e[i].r;}
}
ans ++;
return ;
}
inline void dfs(int x)
{
if(x == n + 1) return check(), void();
dfs(x + 1);
vis[x] = 1;
dfs(x + 1);
vis[x] = 0;
return ;
}
signed main()
{
n = read();
for(int i = 1; i <= n; i ++) e[i] = (node){read(), read()};
sort(e + 1, e + n + 1, cmp);
dfs(1);
cout << ans << endl;
return 0;
}
T2
首先手模一下,可以发现我们每次至少砍一次,那么最多只要 \(\log n\) 轮(上取整)。
然后考虑分几轮搞,既然不大那就直接枚举。
考虑假设一共分 \(k\) 次的话,那么设两次分别分 \(a - 1\) 和 \(a + 1\) 次,那么其实跟分 \(a\) 次是等价的。
所以我们当前枚举到分 \(i\) 轮,那么我们平均每轮分 \(xx = n^{\frac{1}{i}}\) 次,但是这个是下取整,设 \(tm = xx^{i}\) 是我们当前分的次数最多能确定有多少人的情况,那么只要 \(tm\) 小于 \(n\),我们就给其中一轮多分一次。
不难想到在最劣的情况下每一个都多分一次 \(tm\) 就一定比 \(n\) 大了。
复杂度 \(O(T\log^{2}n)\).
/*
* @Author: Aisaka_Taiga
* @Date: 2023-10-06 16:08:40
* @LastEditTime: 2023-10-06 16:22:55
* @LastEditors: Aisaka_Taiga
* @FilePath: \Desktop\T2_100.cpp
* The heart is higher than the sky, and life is thinner than paper.
*/
#include<bits/stdc++.h>
#define int long long
#define N 1000100
using namespace std;
inline int read()
{
int x = 0, f = 1;
char c = getchar();
while(c < '0' || c > '9'){if(c == '-') f = -1; c = getchar();}
while(c <= '9' && c >= '0') x = (x << 1) + (x << 3) + (c ^ 48), c = getchar();
return x * f;
}
inline int ksm(int x, int y)
{
int res = 1;
while(y)
{
if(y & 1) res = res * x;
x = x * x , y >>= 1;
}
return res;
}
signed main()
{
int T = read();
while(T--)
{
int n = read(), b = read(), a = read();
int res = 1LL << 60;//最大值
if(n == 1){cout << "0" << endl; continue;}//就1个那就不用找
int lim = log2(n) + 1;//次数的上限,每轮至少砍一次
for(int i = 1; i <= lim; i ++)//枚举轮数
{//xx是当前人一轮有几个人(下取整),tm是每轮乘起来的最后的能检测的最大人数,K是砍的总次数,
int xx = pow(n, 1.0 / i), tm = ksm(xx, i), K = (xx - 1) * i;
while(tm < n) tm /= xx, tm *= (xx + 1), K ++;//加轮数,最坏都加1 tm一定就大于n了
res = min(res, K * a + b * i);//取最优的答案,i是轮数,K是一共砍了几次
}
cout << res << endl;
}
return 0;
}
赛时暴力代码:
/*
* @Author: Aisaka_Taiga
* @Date: 2023-10-06 09:39:40
* @LastEditTime: 2023-10-06 14:07:42
* @LastEditors: Aisaka_Taiga
* @FilePath: \Desktop\T2.cpp
* The heart is higher than the sky, and life is thinner than paper.
*/
#include <bits/stdc++.h>
#define int long long
#define N 1000100
#define endl '\n'
using namespace std;
inline int read()
{
int x = 0, f = 1;
char c = getchar();
while(c < '0' || c > '9'){if(c == '-') f = -1; c = getchar();}
while(c <= '9' && c >= '0') x = (x << 1) + (x << 3) + (c ^ 48), c = getchar();
return x * f;
}
int T, n, a, b, ans;
inline void dfs(int x, int sum)
{
if(x == 1) return ans = min(sum, ans), void();
int cc = sqrt(x);
for(int i = 2; i <= x; i ++)
{
// if(x % i == 0)
// {
// int c1 = i, c2 = x / i;
// dfs(c2, sum + a * c1 + b);
// dfs(c1, sum + a * c2 + b);
// }
if(x % i == 0) dfs(x / i, sum + a * (i - 1) + b);
else dfs(x / i + 1, sum + a * (i - 1) + b);
}
return ;
}
inline void work()
{
n = read(), b = read(), a = read();
ans = 1e18;
dfs(n, 0);
cout << ans << endl;
return ;
}
signed main()
{
T = read();
while(T --) work();
return 0;
}
/*
1
100000000 12 3
*/
本文来自博客园,作者:北烛青澜,转载请注明原文链接:https://www.cnblogs.com/Multitree/articles/17745016.html
The heart is higher than the sky, and life is thinner than paper.