HNOI2018
Day1
Day2
游戏
https://www.luogu.org/problemnew/show/P4436
前二十分暴力
对于 y <= x 的数据,只要门被上锁,便无法从右向左,从1~n扫一遍很容易得到每个点能遍历的区间的左端点
因为所有钥匙都在门左侧,那么从1一定能走到n,初始 l=1, r=n
再依次枚举起点s,若无法向左走到l,则需要l ~ i - 1这段路上的钥匙的门也无法通过,更新r
考虑到若 rmin< s ,则当前 r 对 s 对应的区间已无限制, r 应取大于 s 的最小值这里我是用堆维护
剩下40分,坑先挖着吧,以后来填
20 + 40 分代码
#include <bits/stdc++.h>
using namespace std;
#define N 1000005
int n, m, Q;
int key[N], ans[N][2];
vector<int> sum[N];
priority_queue<int, vector<int>, greater<int> > q;
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 * 10 + ch - '0'; ch = getchar();}
return x * f;
}
int main()
{
n = read(); m = read(); Q = read();
bool casexy = true;
for (int i = 1; i <= m; i++)
{
int x = read(), y = read();
key[x] = y;
if (x != y) sum[y].push_back(x);
if (x < y) casexy = false;
}
if (casexy)
{
int p = 1;
for (int i = 1; i <= n; i++)//先处理出左端点
{
ans[i][0] = p;
if (key[i]) p = i + 1;
}
int l = 1, r = n; q.push(n);
for (int i = 1; i <= n; i++)
{
while(r < l && !q.empty())
{
q.pop(); r = q.top();
}
if(r < i) {ans[i][1] = i; continue;}
ans[i][1] = r;
while (ans[i + 1][0] > l)
{
for(int j = 0; j < sum[l].size(); j++)
{
r = min(r, sum[l][j]);
q.push(sum[l][j]);
}
l++;
}
}
while (Q--)
{
int x = read(), y = read();
if (ans[x][0] <= y && ans[x][1] >= y) puts("YES"); else puts("NO");
}
}
else
{
for(int i = 1; i <= n; i++) ans[i][0] = ans[i][1] = i;
for(int s = 1; s <= n; s++)
{
int l = s, r = s;
while(l > 1 || r < n)
{
if(l > 1 && (!key[l - 1] || (key[l - 1] >= l && key[l - 1] <= r))) l = ans[l - 1][0];
else if(r < n && (!key[r] || (key[r] >= l && key[r] <= r))) r = ans[r + 1][1];
else break;
}
ans[s][0] = l; ans[s][1] = r;
}
while(Q--)
{
int x = read(), y = read();
if (ans[x][0] <= y && ans[x][1] >= y) puts("YES"); else puts("NO");
}
}
return 0;
}
道路
https://www.luogu.org/problemnew/show/P4438
考场上觉得暴搜打那么多只有20分太不划算,然而同行julao说暴搜有70
喵喵喵???
然后更加ju的julao传授了dp 40行AC代码
我果然还是太菜了啊
#include <bits/stdc++.h>
using namespace std;
#define N 20005
#define M 45
#define inf 1000000000000000
#define ll long long
int n;
int s[N], t[N];
int a[N], b[N], c[N];
ll f[M][M];//f[i][j]表示从当前节点向上有i条公路,j条铁路待修
void dfs(int x, ll T[M][M])
{
if(x < 0)//所有乡村均为叶子节点
{
x *= -1;//节点暴力枚举所有情况
for(int i = 0; i <= 40; i++)
for(int j = 0; j <= 40; j++)
T[i][j] = (ll)c[x] * (a[x] + i) * (b[x] + j);
return;
}
ll l[M][M], r[M][M];
dfs(s[x], l); dfs(t[x], r);
for(int i = 0; i <= 40; i++)//f[x][i][j] 省去一维
for(int j = 0; j <= 40; j++)
T[i][j] = min(l[i][j] + r[i][j + 1], l[i + 1][j] + r[i][j]); //选择公路或铁路进行翻修
}
int main()
{
scanf("%d", &n);
for(int i = 1; i < n; i++) scanf("%d%d", &s[i], &t[i]);//二叉树
for(int i = 1; i <= n; i++) scanf("%d%d%d", &a[i], &b[i], &c[i]);
dfs(1, f);
printf("%lld", f[0][0]);
return 0;
}