该卷卷啦 再摆烂不能要了
A. 游戏
其实我10月份做过这道题 自己做了忘了 再做还读错30min题
容易想到,操作次数之和最后一个不为其它数倍数的数的位置有关
那么,先考虑筛法把所有这样的数找出来,设共有 \(x\) 个
然后显然就可以枚举最后一个的位置,然后组合
更强的结论为
\[\frac{x}{x+1}(n+1)! \]#include <bits/stdc++.h>
using namespace std;
#define int long long
#define ull unsigned long long
#define ALL(a) (a).begin(), (a).end()
#define pb push_back
#define mk make_pair
#define pii pair<int, int>
#define pis pair<int, string>
#define sec second
#define fir first
#define sz(a) int((a).size())
#define Yes cout << "Yes" << endl
#define YES cout << "YES" << endl
#define No cout << "No" << endl
#define NO cout << "NO" << endl
#define debug(x) cerr << #x << ": " << x << endl
#define double long double
#define mms(arr, n) memset(arr, n, sizeof(arr))
#define rep(i, a, n) for (int i = (a); i <= (n); ++i)
#define per(i, n, a) for (int i = (n); i >= (a); --i)
int max(int a, int b)
{
if (a > b)
return a;
return b;
}
int min(int a, int b)
{
if (a < b)
return a;
return b;
}
const int INF = 0x3f3f3f3f3f3f3f3f;
const int MOD = 1000000007;
const int N = 1e7 + 10;
// bool st;
int l, r;
int n;
int fac[N];
bool vis[N];
vector<int> vec;
int cnt = 0;
// bool en;
int fct[10000009], divfct[10000009];
int qpow(int a, int b)
{
int ans = 1;
while (b)
{
if (b & 1)
ans = (ans * a) % MOD;
a = (a * a) % MOD;
b /= 2;
}
return ans;
}
void init()
{
fct[0] = 1;
for (int i = 1; i <= 10000000; i++)
fct[i] = (fct[i - 1] * i) % MOD;
divfct[10000000] = qpow(fct[10000000], MOD - 2);
for (int i = 10000000 - 1; i >= 0; i--)
divfct[i] = (divfct[i + 1] * (i + 1)) % MOD;
}
int C(int x, int y)
{
if (x < 0 || y < 0 || x < y)
return 0;
if (x == y || y == 0)
return 1;
else
return fct[x] * divfct[x - y] % MOD * divfct[y] % MOD;
}
void solve()
{
cin >> l >> r;
init();
n = r - l + 1;
fac[0] = 1;
rep(i, 1, n) fac[i] = fac[i - 1] * i % MOD;
rep(i, l, r)
{
if (!vis[i])
{
cnt++;
vec.push_back(i);
}
for (int x = i; x <= r; x += i)
{
vis[x] = true;
}
}
// cerr << cnt << endl;
int res = 0;
rep(i, cnt, n)
{
(res += i * C(i - 1, cnt - 1) % MOD * fct[cnt] % MOD * fct[n - cnt] % MOD) %= MOD;
// cerr << res << endl;
}
cout << res << endl;
}
signed main()
{
freopen("game.in", "r", stdin);
freopen("game.out", "w", stdout);
// cerr<<(&en-&st)/1024.0/1024.0<<endl;
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int testcase = 1;
// cin >> testcase;
while (testcase--)
solve();
return 0;
}
挖个坑 不会证
B. 最短路
感觉很典的题(可能吧 为什么感觉别人都没见过呢)
很容易想到对于每个点单独算贡献
求出到一个点用 \(k\) 步,\(t=0\) 时的最小距离 \(b\) 是容易的
这样,其实相当于对于每个点,给定若干个 \(y=kx+b\) 的一次函数,求 \(\sum\limits_{x=0}^m \min{(f(x))}\)
明显可以凸包维护
#include <bits/stdc++.h>
using namespace std;
#define int long long
#define ull unsigned long long
#define ALL(a) (a).begin(), (a).end()
#define pb push_back
#define mk make_pair
#define pii pair<int, int>
#define pis pair<int, string>
#define sec second
#define fir first
#define sz(a) int((a).size())
#define Yes cout << "Yes" << endl
#define YES cout << "YES" << endl
#define No cout << "No" << endl
#define NO cout << "NO" << endl
#define debug(x) cerr << #x << ": " << x << endl
#define double long double
#define mms(arr, n) memset(arr, n, sizeof(arr))
#define rep(i, a, n) for (int i = (a); i <= (n); ++i)
#define per(i, n, a) for (int i = (n); i >= (a); --i)
int max(int a, int b)
{
if (a > b)
return a;
return b;
}
int min(int a, int b)
{
if (a < b)
return a;
return b;
}
const int INF = 0x3f3f3f3f3f3f3f3f;
const int MOD = 1000000007;
const int N = 2500 + 10;
const int M = 5000 + 10;
const int inv2 = 500000004;
// bool st;
int n, m, t;
vector<pii> g[N];
int dis[N][M];
pii st[M];
int top = 0;
// bool en;
void solve()
{
cin >> n >> m >> t;
rep(i, 1, m)
{
int u, v, w;
cin >> u >> v >> w;
g[u].push_back({v, w});
g[v].push_back({u, w});
}
memset(dis, 0x3f, sizeof(dis));
dis[1][0] = 0;
int res = 0;
rep(st, 0, m - 1)
{
rep(x, 1, n)
{
for (auto [v, w] : g[x])
{
if (dis[v][st + 1] > dis[x][st] + w)
{
dis[v][st + 1] = dis[x][st] + w;
}
}
}
}
// int res = 0;
rep(i, 2, n)
{
top = 0;
// cerr << i << endl;
per(j, m, 1)
{
// cerr << dis[i][j] << ' ';
while (top > 1 && (__int128)(st[top].second - st[top - 1].second) * (__int128)(j - st[top].first) < (__int128)(dis[i][j] - st[top].second) * (__int128)(st[top].first - st[top - 1].first))
top--;
st[++top] = {j, dis[i][j]};
}
// cerr << endl;
// cerr << top << endl;
// rep(i, 1, top) cerr << st[i].first << ' ' << st[i].second << endl;
// reverse(st + 1, st + top + 1);
int l = 0, r;
rep(j, 1, top)
{
if (l > t)
break;
if (j != top)
r = (st[j + 1].second - st[j].second) / (st[j].first - st[j + 1].first);
else
r = INF;
while (j != top && st[j].first * r + st[j].second <= st[j + 1].first * r + st[j + 1].second)
r++;
r--;
r = min(r, t);
if (r < l)
continue;
res = (res + (l * st[j].first % MOD + st[j].second + r * st[j].first % MOD + st[j].second) % MOD * (r - l + 1) % MOD * inv2 % MOD) % MOD;
l = r + 1;
}
// int p = 1;
// rep(j, 0, t)
// {
// while (p < top && st[p].first * j + st[p].second >= st[p + 1].first * j + st[p + 1].second)
// p++;
// (res += st[p].first * j % MOD + st[p].second) %= MOD;
// }
}
cout << res << endl;
}
signed main()
{
// freopen("a.in", "r", stdin);
// freopen("a.out", "w", stdout);
// cerr<<(&en-&st)/1024.0/1024.0<<endl;
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int testcase = 1;
// cin >> testcase;
while (testcase--)
solve();
return 0;
}
C. 移动箱子
结论1:当前堆有 \(y\) 个,\(lim=k\) 的时候,这一堆产生的贡献是
\[t=\lfloor\frac{y}{k}\rfloor\\ f_y(k)=yt-k\binom{t+1}{2} \]结论2:当存在 \((x_i,y_i),(x_{i+1},y_{i+1})\) 使得从 \(x_i\) 出发向后铺会延伸到 \(x_{i+1}\) ,这两堆等价于 \((x_i,y_i+y_{i+1})\) , 可以直接合并
从大到小枚举 \(lim\), 每次用链表合并,更新代价
#include <bits/stdc++.h>
using namespace std;
#define int long long
#define ull unsigned long long
#define ALL(a) (a).begin(), (a).end()
#define pb push_back
#define mk make_pair
#define pii pair<int, int>
#define pis pair<int, string>
#define sec second
#define fir first
#define sz(a) int((a).size())
#define Yes cout << "Yes" << endl
#define YES cout << "YES" << endl
#define No cout << "No" << endl
#define NO cout << "NO" << endl
#define debug(x) cerr << #x << ": " << x << endl
#define double long double
#define mms(arr, n) memset(arr, n, sizeof(arr))
#define rep(i, a, n) for (int i = (a); i <= (n); ++i)
#define per(i, n, a) for (int i = (n); i >= (a); --i)
int max(int a, int b) {
if (a > b)
return a;
return b;
}
int min(int a, int b) {
if (a < b)
return a;
return b;
}
const int INF = 0x3f3f3f3f3f3f3f3f;
const int MOD = 998244353;
const int N = 2e5 + 10;
// bool st;
int n, m;
pii p[N];
int nxt[N], pre[N];
int x[N], y[N], z[N];
vector<int> vec[N];
bool vis[N];
int s[N], t[N];
int cnt;
// bool en;
int binom(int x) {
x = (x % MOD + MOD) % MOD;
return x * (x + 1) / 2 % MOD;
}
void add(int &x, int y) { x = ((x % MOD + (y % MOD + MOD) % MOD) % MOD + MOD) % MOD; }
void solve() {
cin >> n >> m;
cnt = n;
rep(i, 1, n) cin >> p[i].first >> p[i].second;
sort(p + 1, p + n + 1);
nxt[0] = 1;
rep(i, 1, n) {
nxt[i] = i + 1;
pre[i] = i - 1;
}
nxt[n] = 0;
rep(i, 1, n) {
x[i] = p[i].first;
y[i] = p[i].second;
}
rep(i, 1, n) { vec[y[i]].push_back(i); }
per(i, m, 1) {
for (auto v : vec[i]) {
if (vis[v])
continue;
add(s[i], -(z[v] % MOD) * (y[v] % MOD) % MOD);
add(t[i], -binom(z[v]));
z[v] = y[v] / i;
if (y[v] / (z[v] + 1))
vec[y[v] / (z[v] + 1)].push_back(v);
add(s[i], (z[v] % MOD) * (y[v] % MOD) % MOD);
add(t[i], binom(z[v]));
}
for (auto v : vec[i]) {
if (vis[v])
continue;
for (int k = nxt[v]; k && x[v] + z[v] >= x[k]; k = nxt[v]) {
add(s[i], -(z[v] % MOD) * (y[v] % MOD) % MOD);
add(t[i], -binom(z[v]));
add(s[i], -(z[k] % MOD) * (y[k] % MOD) % MOD);
add(t[i], -binom(z[k]));
cnt++;
x[cnt] = x[v];
y[cnt] = y[v] + y[k];
z[cnt] = y[cnt] / i;
add(s[i], (z[cnt] % MOD) * (y[cnt] % MOD) % MOD);
add(t[i], binom(z[cnt]));
add(s[i], -(y[k] % MOD) * ((x[k] - x[v]) % MOD) % MOD);
if (y[cnt] / (z[cnt] + 1))
vec[y[cnt] / (z[cnt] + 1)].push_back(cnt);
vis[v] = vis[k] = true;
nxt[pre[v]] = cnt;
pre[nxt[k]] = cnt;
pre[cnt] = pre[v];
nxt[cnt] = nxt[k];
v = cnt;
}
}
vec[i].clear();
}
per(i, m, 1) {
add(s[i], s[i + 1]);
add(t[i], t[i + 1]);
}
rep(i, 1, m) { cout << ((s[i] + MOD - t[i] * i % MOD) % MOD + MOD) % MOD << ' '; }
}
signed main() {
freopen("boxes.in", "r", stdin);
freopen("boxes.out", "w", stdout);
// cerr<<(&en-&st)/1024.0/1024.0<<endl;
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int testcase = 1;
// cin >> testcase;
while (testcase--) solve();
return 0;
}
被卡常了 还 TLE
这呢qwq
我与凸包不共戴天!太难调了qwq
标签:cnt,return,int,st,20240118,MOD,define From: https://www.cnblogs.com/xiaruize/p/17973277