CXJY-Day 11
T1
维护一个后缀和差分数组,从后往前算出每个操作的执行次数
然后正着扫描,做差分求出数组,做前缀和即可
注意要取模
其实$n log _n$也能过了
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
struct node
{
int a, l, r;
} op[1000005];
int n, m;
ll ct[2][1000005], mod = 1e9 + 7;
void add(int k, int x, ll v)
{
for (; x <= m; x += x & -x)
{
ct[k][x] += v;
if (ct[k][x] >= mod)
ct[k][x] -= mod;
if (ct[k][x] < 0)
ct[k][x] += mod;
}
}
ll query(int k, int x)
{
ll ans = 0;
for (; x; x -= x & -x)
{
ans += ct[k][x];
if (ans >= mod)
ans -= mod;
if (ans < 0)
ans += mod;
}
return ans;
}
int main()
{
freopen("operate.in", "r", stdin);
freopen("operate.out", "w", stdout);
cin >> n >> m;
for (int i = 1; i <= m; ++i)
{
scanf("%d%d%d", &op[i].a, &op[i].l, &op[i].r);
}
add(0, 1, 1);
add(0, m + 1, -1);
for (int i = m; i >= 1; --i)
{
if (op[i].a == 2)
{
ll t = query(0, i);
add(0, op[i].l, t);
add(0, op[i].r + 1, -t);
}
}
for (int i = 1; i <= m; ++i)
{
if (op[i].a == 1)
{
ll t = query(0, i);
ct[1][op[i].l] += t;
ct[1][op[i].r + 1] -= t;
}
}
for (int i = 1; i <= n; ++i)
{
ct[1][i] += ct[1][i - 1];
if (ct[1][i] >= mod || ct[1][i] < 0)
ct[1][i] %= mod;
if (ct[1][i] < 0)
ct[1][i] += mod;
}
ll ans = 0;
for (int i = 1; i <= n; ++i)
{
ans ^= ct[1][i];
}
cout << ans << endl;
return 0;
}
T2
50
定义$dp[i][j]$表示在第一天已经用了j小时,完成i子树的题目最小还要多少天多少小时(pair类型)
考虑m较小,直接暴力枚举m!即可
100
状压所有儿子,$dp[i][j]$为在第一天用了j个小时,完成i集合内的子树中的题目至少需要多少天多少小时
向后转移即可
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int, int> pii;
int cnt, head[5005], w[5005], t[5005], n, h;
pii dp[5005][25], f[1025][25];
vector<int> v[5005];
void update(pii x, pii &y)
{
if (y.first == -1)
y = x;
else if ((y.first == x.first && y.second > x.second) || y.first > x.first)
y = x;
}
void dfs(int x)
{
for (int i = 0; i < w[x]; i++)
{
dfs(v[x][i]);
}
int full = (1 << w[x]) - 1;
for (int i = 0; i <= full; ++i)
{
for (int j = 0; j < h; ++j)
{
f[i][j] = pii(-1, -1);
}
}
for (int i = 0; i + t[x] < h; ++i)
{
f[0][i] = pii(0, i + t[x]);
}
f[0][h - t[x]] = pii(1, 0);
for (int i = h - t[x] + 1; i < h; ++i)
{
if (t[x] < h)
f[0][i] = pii(1, t[x]);
else
f[0][i] = pii(2, 0);
}
for (int s = 0; s < h; ++s)
{
for (int mask = 0; mask <= full; ++mask)
{
for (int j = 0; j < w[x]; ++j)
{
if ((mask >> j) & 1)
continue;
int a = f[mask][s].first + dp[v[x][j]][f[mask][s].second].first;
int b = dp[v[x][j]][f[mask][s].second].second;
update(pii(a, b), f[mask | (1 << j)][s]);
}
}
}
for (int i = 0; i < h; ++i)
dp[x][i] = f[full][i];
}
int main()
{
freopen("coding.in", "r", stdin);
freopen("coding.out", "w", stdout);
cin >> n >> h;
for (int i = 1; i <= n; ++i)
scanf("%d", &t[i]);
for (int i = 1; i <= n; ++i)
{
scanf("%d", &w[i]);
for (int j = 1; j <= w[i]; ++j)
{
int x;
scanf("%d", &x);
v[i].push_back(x);
}
}
dfs(1);
if (dp[1][0].second)
dp[1][0].first++;
cout << dp[1][0].first << endl;
return 0;
}
T3
求出从s出发到每个点经过i条权值为x的边的最短路径
然后维护一个凸包(单调栈)即可(详见Day3-T1)
本题也可直接计算出每一个一次函数的作用范围,即$ij$与它的最右交点
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int, int> pii;
struct node
{
int Next, y, v;
} Pth[10005];
int cnt, head[505], n, m;
ll dis[505][505], INF = 0x3f3f3f3f3f3f3f3f;
bool v[505][505];
void add(int x, int y, int v)
{
cnt++;
Pth[cnt].Next = head[x];
Pth[cnt].y = y;
Pth[cnt].v = v;
head[x] = cnt;
}
char s[10];
void spfa(int s)
{
memset(dis, -1, sizeof dis);
memset(v, 0, sizeof v);
dis[s][0] = 0;
queue<pii> q;
q.push(pii(s, 0));
while (!q.empty())
{
int x = q.front().first;
int st = q.front().second;
q.pop();
if (st > 500)
continue;
v[x][st] = 0;
for (int i = head[x]; i; i = Pth[i].Next)
{
int y = Pth[i].y;
int nt = st;
if (Pth[i].v == 0)
nt++;
if (dis[y][nt] == -1 || Pth[i].v + dis[x][st] < dis[y][nt])
{
dis[y][nt] = Pth[i].v + dis[x][st];
if (!v[y][nt])
{
q.push(pii(y, nt));
v[y][nt] = 1;
}
}
}
}
}
int main()
{
freopen("dist.in", "r", stdin);
freopen("dist.out", "w", stdout);
cin >> n >> m;
for (int i = 1; i <= m; ++i)
{
int x, y, v;
scanf("%d%d%s", &x, &y, s + 1);
if (s[1] == 'x')
{
add(x, y, 0);
}
else
{
sscanf(s + 1, "%d", &v);
add(x, y, v);
}
}
int q;
cin >> q;
while (q--)
{
int s, t;
scanf("%d%d", &s, &t);
spfa(s);
int fl = 0;
for (int i = 0; i <= n; ++i)
{
if (dis[t][i] != -1)
fl = 1;
}
if (fl == 0)
{
puts("0 0");
continue;
}
else if (dis[t][0] == -1)
{
puts("inf");
continue;
}
else
{
ll ans2 = 0, ans1 = 0, last = 0, naxl;
for (int i = 0; i <= n; ++i)
{
ll l = 1, r = INF;
if (dis[t][i] == -1)
continue;
for (int j = 0; j < i; ++j)
{
if (dis[t][j] == -1)
continue;
ll rs = (dis[t][j] - dis[t][i]) / (i - j);
if ((dis[t][j] - dis[t][i]) % (i - j) == 0)
rs--;
r = min(r, rs);
}
for (int j = i + 1; j <= n; ++j)
{
if (dis[t][i] == -1)
continue;
ll rs = (dis[t][i] - dis[t][j]) / (j - i);
if ((dis[t][i] - dis[t][j]) % (j - i))
rs++;
l = max(l, rs);
}
if (l <= r)
{
if (i)
ans1 += (r - l + 1), ans2 += (ll)(r - l + 1) * dis[t][i] + (ll)i * (l + r) * (r - l + 1) / 2;
else
ans1++, ans2 += dis[t][i];
}
}
printf("%lld %lld\n", ans1, ans2);
}
}
return 0;
}
背包
梦幻岛宝珠
Cutting Grass(Topcoder SRM 517 DIV2 1000 CuttingGrass)
Codeforces 808E Selling Souvenirs
hdu6125 Free from square
本作品采用知识共享署名-非商业性使用-相同方式共享 3.0 未本地化版本许可协议进行许可。
本文链接:https://hs-blog.axell.top/archives/cxjy-day-11/