Live2D

2022-02-06 集训题解

排队

link

Desciption#

n,m105

Solution#

不难注意到的是,我们假设 fii 之前 ai 的值的个数,那么我们需要满足:

i=1nifi=i=1nimin(i,ai)

又因为我们可以知道 fimin(i,ai),所以我们对于每一个 i 都有 fi=min(i,ai)

考虑如何构造这样的 a 。可以发现,我们选了一个 ai 就将 ai 这个位置赋值为 1。那么,fi=i 就是选一个比最大值大的值,fi=ai 就是选第一个空位。

考虑到我们可以用 (i,v) 来表示第 i 步最大值为 v,那么找第一个空位就是向右走一步,找最大值就是向上走若干步。所以答案就是从 (0,nmaxv) 出发到 (nm,nm),且不能低于 y=x 这条直线的方案数,直接用卡塔兰数的方法来就好了。

Code#

Copy
#include <bits/stdc++.h> using namespace std; #define Int register int #define mod 1000000007 #define MAXN 200005 template <typename T> inline void read (T &t){t = 0;char c = getchar();int f = 1;while (c < '0' || c > '9'){if (c == '-') f = -f;c = getchar();}while (c >= '0' && c <= '9'){t = (t << 3) + (t << 1) + c - '0';c = getchar();} t *= f;} template <typename T,typename ... Args> inline void read (T &t,Args&... args){read (t);read (args...);} template <typename T> inline void write (T x){if (x < 0){x = -x;putchar ('-');}if (x > 9) write (x / 10);putchar (x % 10 + '0');} template <typename T> inline void chkmax (T &a,T b){a = max (a,b);} template <typename T> inline void chkmin (T &a,T b){a = min (a,b);} int n,m,a[MAXN],fac[MAXN],ifac[MAXN]; int mul (int a,int b){return 1ll * a * b % mod;} int dec (int a,int b){return a >= b ? a - b : a + mod - b;} int add (int a,int b){return a + b >= mod ? a + b - mod : a + b;} int qkpow (int a,int b){ int res = 1;for (;b;b >>= 1,a = mul (a,a)) if (b & 1) res = mul (res,a); return res; } void Add (int &a,int b){a = add (a,b);} void Sub (int &a,int b){a = dec (a,b);} struct Bit_Tree{ int sum[MAXN]; int lowbit (int x){return x & (-x);} void modify (int x,int v){for (Int i = x;i <= n;i += lowbit (i)) sum[i] += v;} int query (int x){int res = 0;for (Int i = x;i;i -= lowbit (i)) res += sum[i];return res;} }tree; int binom (int a,int b){ return a >= b ? mul (fac[a],mul (ifac[b],ifac[a - b])) : 0; } signed main(){ freopen ("queue.in","r",stdin); freopen ("queue.out","w",stdout); read (n,m); for (Int i = 1;i <= m;++ i) read (a[i]); int up = 2 * n; fac[0] = 1;for (Int i = 1;i <= up;++ i) fac[i] = mul (fac[i - 1],i); ifac[up] = qkpow (fac[up],mod - 2);for (Int i = up;i;-- i) ifac[i - 1] = mul (ifac[i],i); int maxv = 0,tot; for (Int i = 1;i <= m;++ i) chkmax (maxv,a[i]); for (Int i = 1;i <= m;++ i){ tree.modify (a[i],1); if (tree.query (a[i]) != min (i,a[i])) return puts ("0") & 0; } tot = n - maxv;int all = n - m; write (dec (binom (all + tot,all),binom (all + tot,all + 1))); return 0; }

论文查重

Solution#

太水了,懒得说了

烽火戏诸侯

link

Description#

Solution#

有一个奇怪的贪心,就是说我们一开始先对任意相邻两项都移动到中心,直到不能移动为止。然后我们就对最大最小值进行操作,可以让他们两个向中间动一个,但是中间的节点并不改变。

优化的话,可以发现第一步我们可以使用增量法,那么只需要维护每个斜率为 1 的段的起点即可,第二步直接左右向中间移动即可。

Code#

Copy
#include <bits/stdc++.h> using namespace std; #define Int register int #define int long long #define MAXN 1000005 #define ll long long template <typename T> inline void read (T &t){t = 0;char c = getchar();int f = 1;while (c < '0' || c > '9'){if (c == '-') f = -f;c = getchar();}while (c >= '0' && c <= '9'){t = (t << 3) + (t << 1) + c - '0';c = getchar();} t *= f;} template <typename T,typename ... Args> inline void read (T &t,Args&... args){read (t);read (args...);} template <typename T> inline void write (T x){if (x < 0){x = -x;putchar ('-');}if (x > 9) write (x / 10);putchar (x % 10 + '0');} template <typename T> inline void chkmax (T &a,T b){a = max (a,b);} template <typename T> inline void chkmin (T &a,T b){a = min (a,b);} int n,top,a[MAXN],sta[MAXN],tot[MAXN]; struct Bit_Tree{ int sum[MAXN]; int lowbit (int x){return x & (-x);} void modify (int x,int v){for (Int i = x;i <= 1e6;i += lowbit (i)) sum[i] += v;} int query (int x){int res = 0;for (Int i = x;i;i -= lowbit (i)) res += sum[i];return res;} void change (int l,int r){modify (l,1),modify (r + 1,-1);} }t; signed main(){ freopen ("balefire.in","r",stdin); freopen ("balefire.out","w",stdout); read (n); for (Int i = 1;i <= n;++ i) read (a[i]); sort (a + 1,a + n + 1),sta[top = 1] = 1; ll ans = 0; for (Int i = 2;i <= n;++ i){ int pos = sta[top],lstv = a[i - 1] + t.query (i - 1); while (pos != 1 && a[i] - (i - pos) >= lstv + 1) a[i] -= i - pos,t.modify (pos,1),lstv ++,ans += 1ll * (i - pos) * (i - pos + 1) / 2,pos = sta[-- top]; if (top == 1){ int tim = (a[i] - lstv) / i; lstv += tim,a[i] -= tim * (i - 1),t.modify (1,tim),ans += tim * 1ll * (i - 1) * i / 2; } if (a[i] != lstv){ if (a[i] > lstv + 1){ int d = a[i] - lstv - 1; t.change (pos,pos + d - 1),a[i] -= d,ans += 1ll * (i - pos) * (i - pos + 1) / 2 - 1ll * (i - pos - d) * (i - pos - d + 1) / 2; if (pos != 1) -- top; sta[++ top] = pos + d; } } else sta[++ top] = i; a[i] -= t.query (i); } for (Int i = 1;i <= n;++ i) a[i] += t.query (i),tot[a[i]] ++; int miv = a[1],mxv = a[n]; while (miv + 1 < mxv){ int tim = mxv - miv - 1; if (tot[miv] < tot[mxv]) ans += tim * tot[miv],tot[mxv] -= tot[miv],tot[mxv - 1] += tot[miv],tot[miv + 1] += tot[miv],tot[miv] = 0,miv ++; else ans += tim * tot[mxv],tot[miv] -= tot[mxv],tot[miv + 1] += tot[mxv],tot[mxv - 1] += tot[mxv],tot[mxv] = 0,mxv --; } write (ans),putchar ('\n'); return 0; }
posted @   Dark_Romance  阅读(37)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通
点击右上角即可分享
微信分享提示
CONTENTS