今天的题还是一如既往的良心,结果却不尽人意
诶,菜鸡选手在线嘲讽自己
T1 小明搬家(box)
这个题目是比较适宜的T1
把我这种菜鸡区分掉了
考场以为是个小sb题,然后就没检查
结果大数据都跪了。
菜!
首先处理每个人移走一个箱子的结果
然后后面的每 (k) 个箱子的都是重复的,可以直接累加
如果还有剩余那么就找到那个最慢的一个把箱子扛上来的人
#include <bits/stdc++.h>
using namespace std;
#define int long long
#define rep(i, a, b) for (int i = a; i <= b; i++)
#define per(i, a, b) for (int i = a; i >= b; i--)
#define siz(a) (int)a.size()
#define pb push_back
#define mp make_pair
#define ll long long
#define fi first
#define se second
const int N = 500100;
int n, k, m, ans ;
int a[N], b[N] ;
priority_queue <int, vector <int>, greater<int> > q ;
int cmp(int a, int b) {
return a < b ;
}
signed main() {
// freopen("box.in", "r", stdin) ;
// freopen("box.out", "w", stdout) ;
scanf("%lld%lld%lld", &n, &k, &m) ;
int t = 0 ;
rep(i, 1, k) {
scanf( "%lld%lld" , &a[i] , &b[i]) ;
if (b[i]) a[i] = a[i] - 1 + n - 1 ;
else {
t = max(t, n - a[i]) ;
a[i] = 2 * (n - 1) + n - a[i] ;
}
}
ll ans = 0 ;
ans += 2 * (n - 1) * (m / k) ;
m %= k ;
if (m != 0) {
sort(a + 1, a + k + 1, cmp) ;
t = max(a[m], t) ;
}
ans += t ;
printf("%lld", ans) ;
return 0 ;
}
T2 圆圈舞蹈
这个题目可以用O(n)的 two-pointers 做
但是我这个菜鸡自然想到的是 (O(nlogn)) 的二分
首先倍长一段
然后我们找到那个以 (i) 为起点和终点的序列
查找那个距离最大的点,二分实现
代码里的二分看着很假,用着海星,。em
#include <bits/stdc++.h>
using namespace std;
#define rep(i, a, b) for (int i = a; i <= b; i++)
#define per(i, a, b) for (int i = a; i >= b; i--)
#define siz(a) (int)a.size()
#define pb push_back
#define mp make_pair
#define ll long long
#define fi first
#define se second
const int iinf = 0x3f3f3f3f ;
const int N = 200010 ;
int n ;
ll ans ;
ll a[N], sum[N] ;
signed main() {
scanf("%d", &n) ;
rep(i, 1, n) scanf("%lld", &a[i]) ;
rep(i, 1, n) a[i + n] = a[i] ;
rep(i, 1, 2 * n) sum[i] = sum[i - 1] + a[i] ;
rep(i, 1, n) {
ll cur = 0 ;
int l = i, r = i + n ;
ll Min = 1e17 ;
while (l <= r) {
int mid = (l + r) >> 1 ;
int x = sum[mid] - sum[i], y = sum[i + n] - sum[mid] ;
if (abs(x - y) < Min) {
Min = abs(x - y) ;
cur = min(x, y) ;
ans = max(ans, cur) ;
}
if (l == mid) break ;
if (x < y) l = mid ;
else r = mid ;
}
}
printf("%lld
", ans) ;
return 0 ;
}
T3 物流运输(trans)
这个题目好像是某省省选题,结果就被机房大部分人切了
蛮简单的
(n,m) 超小,随便写
感觉可以加强到 500,500,这样可以把状压的代码卡掉
预处理以单一路线从 (i) 天到第 (j) 天的最短路
(即第 (i) 天到第 (j) 天中有被封闭的路都不能走)
考虑dp
介绍一种 (O(n^2))的方法
(dp[i]) 表示处理到第 (i) 天的最小花费
考虑第i天,要么是从 (1) 到 (i) 都是一成不变,要么中间变
枚举最近的一次变化,然后取 (min) 即可
转移方程见代码
#include <bits/stdc++.h>
using namespace std;
#define rep(i, a, b) for (int i = a; i <= b; i++)
#define per(i, a, b) for (int i = a; i >= b; i--)
#define siz(a) (int)a.size()
#define pb push_back
#define mp make_pair
#define ll long long
#define fi first
#define se second
const int N = 110 ;
struct Edge {
int t, v ;
} ;
vector <Edge> e[N] ;
int n, k, m, E, d ;
bool ok[N][N] ;
bool vis[N], valid[N] ;
int dis[N] ;
queue <int> q ;
int cost[N][N] ;
ll dp[N] ;
int spfa(int a, int b) {
memset(vis, 0, sizeof(vis)) ;
memset(dis, 0x3f, sizeof(dis)) ;
memset(valid, true, sizeof(valid)) ;
while (!q.empty()) q.pop() ;
rep(i, 1, m)
rep(j, a, b)
if (!ok[i][j])
valid[i] = false ; q.push(1) ;
vis[1] = 1 ; dis[1] = 0 ;
while (!q.empty()) {
int u = q.front() ; q.pop() ;
vis[u] = 0 ;
rep(i, 0, siz(e[u]) - 1) {
int v = e[u][i].t, val = e[u][i].v ;
if (!valid[v]) continue ;
if (dis[v] > dis[u] + val) {
dis[v] = dis[u] + val ;
if (!vis[v]) {
vis[v] = 1 ;
q.push(v) ;
}
}
}
}
return dis[m] ;
}
signed main() {
freopen("trans.in", "r", stdin) ;
freopen("trans.out", "w", stdout) ;
scanf("%d%d%d%d", &n, &m, &k, &E) ; // n 表示货物运输所需天数,m 表示码头总数,K 表示每次修改运输路线所需成本。
rep(i, 1, E) {
int u, v, w ; scanf("%d%d%d", &u, &v, &w) ;
e[u].pb((Edge) {v, w}) ;
e[v].pb((Edge) {u, w}) ;
}
scanf("%d", &d) ;
memset(ok, true, sizeof(ok)) ;
rep(i, 1, d) {
int a, b, p ; scanf("%d%d%d", &p, &a, &b) ;
rep(j, a, b) ok[p][j] = false ;
}
rep(i, 1, n)
rep(j, 1, n)
cost[i][j] = spfa(i, j) ;
rep(i, 1, n) {
dp[i] = 1ll * cost[1][i] * i ; // 1~i
rep(j, 1, i - 1) dp[i] = min(dp[i], dp[j] + k + 1ll * cost[j + 1][i] * (i - j)) ; // 1~j,j+1~i
}
printf("%lld
", dp[n]) ;
return 0 ;
}
/*
5 5 10 8
1 2 1
1 3 3
1 4 2
2 3 2
2 4 4
3 4 1
3 5 2
4 5 2
4
2 2 3
3 1 1
3 3 3
4 4 5
*/