孝感市网站建设_网站建设公司_动画效果_seo优化
2026/1/16 22:20:23 网站建设 项目流程

Educational Codeforces Round 186

C - Production of Snowmen

给定三个分别有 $n$ 个元素的环 $a,b,c$,现在要选择一个三元组 $(i,j,k),1\le i,j,k\le n$,使得 $(a_i,b_j,c_k),(a_{i+1},b_{j+1},c_{k+1}),\cdots,(a_{i+n-1},b_{j+n-1},c_{k+n-1})$ 都满足 $a<b<c$,问合法的三元组个数。

$1\le n\le 5\times 10^3$。

先考虑只有两个环的情况怎么做。

先断环为链,不难想到先 $O(n^2)$ 枚举起点再 $O(n)$ 比较,总共 $O(n^3)$。

但会发现有很多重复计算的东西。由于这玩意类似滑动窗口,考虑换一下枚举的东西,我们先枚举两个起点 $i,j$ 的距离 $dis$,然后再枚举 $i$。你会发现当我们的 $i$ 往后挪一位时,$j$ 也同步挪一位,此时刚好有一对数进入了我们的滑动窗口,有一对数出去了,那我们只需要比较出去的这对和进来的这对就行了。这样下来时间复杂度是 $O(n^2)$ 的。

于是我们可以求出来对于每个 $j$,合法的二元组 $(j,k),b_j<c_k$ 的个数,这里设为 $p_j$。我们对 $a$ 环和 $b$ 环施以同样的比较方式,如果有两个起点 $i,j$ 合法,我们为答案加上 $p_j$ 即可。

总时间复杂度 $O(n^2)$。

ll T;
ll n,a[N*2],b[N*2],c[N*2];
ll p[N*2];
void solve(){cin>>n;for(ll i=1;i<=n;i++) p[i]=0;for(ll i=1;i<=n;i++){ cin>>a[i]; a[i+n]=a[i]; }for(ll i=1;i<=n;i++){ cin>>b[i]; b[i+n]=b[i]; }for(ll i=1;i<=n;i++){ cin>>c[i]; c[i+n]=c[i]; }for(ll dis=0;dis<n;dis++){ll cnt=0;for(ll i=1;i<=n;i++){ll j=i+dis;if(b[i]>=c[j]) cnt++;}if(!cnt) p[1]++;for(ll i=2,j=dis+2;i<=n;i++,j++){if(b[i-1]>=c[j-1]) cnt--;if(j>n) j-=n;if(b[i+n-1]>=c[j+n-1]) cnt++;if(!cnt) p[i]++;}}for(ll i=1;i<=n;i++) p[i+n]=p[i];ll ans=0;for(ll dis=0;dis<n;dis++){ll cnt=0;for(ll i=1;i<=n;i++){ll j=i+dis;if(a[i]>=b[j]) cnt++;}if(!cnt) ans+=p[dis+1];for(ll i=2,j=dis+2;i<=n;i++,j++){if(a[i-1]>=b[j-1]) cnt--;if(j>n) j-=n;if(a[i+n-1]>=b[j+n-1]) cnt++;if(!cnt) ans+=p[j];}}cout<<ans<<"\n";
}

D - Christmas Tree Decoration

现在有 $n+1$ 个从 $0$ 编号到 $n$ 的盒子,每个盒子里有 $a_i$ 个装饰品。有 $n$ 个人,按照排列 $p$ 的顺序,从 $p_1$ 到 $p_n$ 依次轮流拿装饰品挂上去,第 $i$ 个人有两种选择:

  • 盒子 $0$ 里选一个礼物挂上去;
  • 盒子 $i$ 里选一个礼物挂上去。

如果没有出现一个人没有礼物可挂的情况,这个排列就是合法的,问合法的排列数,答案模 $998244353$。

$1\le T\le 5000,1\le n\le 50$。

你发现 $0$ 号盒子可以看作一个备用盒子嘛,低保金属于是。

于是发现,每次等到第 $i$ 个人对应的盒子里没有了再去拿 $0$ 号盒子里的东西,一定不劣,相当于按需所取。于是题意转化为,求轮空次数 $\le a_0$ 的排列数。

首先什么时候轮空次数最少?你会发现一定是 $p_i$ 按照 $a_{p_i}$ 从大到小的顺序排列,例如 3 3 2 1 1,你会发现这样子后面的 2 1 1 就可以少轮空一次。此时总轮空次数为
$$
p=\sum_{i=1,a_i<maxa}maxa-1-a_i
$$
其中 $maxa=\max a$。

因此我们先把 $a_1\sim a_n$ 排个序,这样不影响对答案的计数。

然后你会发现,每当有一个小于 $maxa$ 的元素被丢到 $maxa$ 的前面去,如 1 3 3 2 13 2 3 1 1,轮空次数就会加一,因此我们枚举轮空次数,设轮空次数最小值为上文的 $p$,小于 $maxa$ 的元素个数为 $nmx$,等于 $maxa$ 的元素个数为 $mx$,则方案数可以推出来:
$$
\sum_{i=p}^{\min(a_0,p+nmx)}\binom{nmx}{i-p}\cdot(mx-1+i-p)!\cdot mx\cdot (nmx-(i-p))
$$
意思是:

  • 最右边的 $maxa$ 元素之前的所有元素可以乱排;
  • 最右边的 $maxa$ 元素有 $mx$ 种选法;
  • 右边的数可以乱排。

时间复杂度 $O(Tn)$。

void solve(){cin>>n>>a0;fac[0]=1;for(ll i=1;i<=n;i++){cin>>a[i];fac[i]=fac[i-1]*i%P;}finv[n]=qpow(fac[n],P-2);for(ll i=n-1;i>=0;i--) finv[i]=finv[i+1]*(i+1)%P;sort(a+1,a+n+1,cmp);ll mxcnt=0,nmxcnt=0,bas=0;for(ll i=1;i<=n;i++){if(a[i]==a[1]) mxcnt++;else nmxcnt++,bas+=a[1]-1-a[i];}ll ans=0;for(ll i=0;i+bas<=a0&&i<=nmxcnt;i++) ans=(ans+C(i,nmxcnt)*mxcnt%P*fac[mxcnt-1+i]%P*fac[nmxcnt-i]%P)%P;cout<<ans<<"\n";
}

E - New Year's Gifts

看错题了。

小 M 有 $n$ 个朋友,他要给他的每个朋友送一份新年礼物,他已经给他们分别选好了礼物,价值为 $y_i$。

同时,现在有 $m$ 个免费的礼盒,每个礼盒颜值为 $x_i$,一个礼物可以选择包装,也可以不包装。

一个朋友会开心,以下条件满足其一即可:

  • 礼物价值至少 $z_i(z_i>y_i)$;
  • 礼盒颜值至少 $x_i$。

现在小 $M$ 手上有 $k$ 个金币,问最多能让多少朋友开心。

$1\le n,m\le 2\times 105,\sum\limits_{i=1}y_i \le k\le 10^{15}$。

先把底款 $y_i$ 付了,操作一转化成加钱,加 $z_i'=z_i-y_i$。

首先这个礼盒居然是免费的,不用白不用,把这些礼盒分配给 $z_i'$ 最大的那几个一定不劣,用 multiset 维护最小的大于等于其 $x_i$ 的礼盒即可。剩下的钱 $k'$ 从小到大给最小的几个 $z_i'$ 加钱就行了。

ll n,m,k,vis[N];
multiset<ll> box;
struct Node{ll x,z;
}a[N];
bool cmp(Node X,Node Y){return X.z<Y.z;
}
void solve(){box.clear();cin>>n>>m>>k;for(ll i=1;i<=m;i++){ll pp; cin>>pp;box.insert(pp);}for(ll i=1;i<=n;i++){ll x,y,z; cin>>x>>y>>z;z-=y,k-=y;a[i]=(Node){x,z};vis[i]=0;}sort(a+1,a+n+1,cmp);ll ans=0;for(ll i=n;i>=1;i--){auto it=box.lower_bound(a[i].x);if(it==box.end()) continue;ans++,vis[i]=1;box.erase(it);}for(ll i=1;i<=n;i++){if(vis[i]) continue;if(k>=a[i].z){ans++;k-=a[i].z;}}cout<<ans<<"\n";
}

F - Christmas Reindeer

给定 $n$ 只鹿,每只鹿能力值为 $2^{c_i}$,有 $m$ 次三种询问:

  1. 添加一只能力值为 $2^x$ 的鹿;
  2. 移除一只能力值为 $2^x$ 的鹿($x$ 均 $\le 60$);
  3. 定义一群鹿的承载量如下,将它们的能力值从大到小排序,其总承载力为 $S_0+\lfloor\frac {S_1}{2^1}\rfloor+\lfloor\frac {S_2}{2^2}\rfloor+\cdots+\lfloor\frac {S_{|S|}}{2^{|S|}}\rfloor$,问你有多少种选择方案使得鹿的承载力大于等于 $x(1\le x\le 1\times 10^{18})$。

$n,m\le 3\times 10^5$

首先你拿一个桶去存能力值,这里记作 ${cnt_i }$。

接着你考虑一种能力值的累计方案 $r_i$ 使得其承载力刚好等于 $x$,这里 $r_i$ 表示能力值为 $i$ 的有多少条鹿。

你会发现,只要字典序大于等于这玩意的累计方案,不都可以吗??因此我们对这个计数就行了,考虑枚举啥,自然想到枚举第一个大于 $r_i$ 的位置 $i$,此时这个累计方案被分为了三段。

$\text{Part A}$:位置在 $i$ 之前的。

随便选,设 $sum_i$ 为 $\sum\limits_{i=1}^n cnt_i$,则有 $a=2^{sum_{i-1}}$。

$\text{Part B}$:位置 $i$。

此时要求这个位置选的鹿的个数必须大于 $r_i$。则有
$$
b=\sum_{j=r_i+1}^{cnt_i}\binom{cnt_i}{j}
$$
但是这样有个问题,就是会枚举两次 $\log V$,复杂度要炸。

因此换一下枚举的东西,正难则反,一个很巧妙的转化,就可以把时间复杂度通过 $\sum r_i$ 弄到均摊的 $\log V$。
$$
b=2{cnt_i}-\sum_{j=0}\binom{cnt_i}{j}
$$
哦耶。

$\text{Part C}$:位置在 $i$ 之后的。

必须和 $r_i$ 一致。
$$
c=\sum_{j=i+1}^{60}\binom{cnt_j}{r_j}
$$
预处理后缀即可免去再套一层 $\log V$。

答案是 $abc$。

总复杂度 $O(n\log V)$。

ll qpow(ll a,ll k){ll res=1;while(k){if(k&1) res=res*a%P;a=a*a%P,k>>=1;}return res;
}
ll fac[N<<1],finv[N<<1];
ll C(ll a,ll b){if(a>b) return 0;return fac[b]*finv[a]%P*finv[b-a]%P;
}
ll T,n,m;
ll tong[70],r[70];
ll suf[70];
void solve(){memset(tong,0,sizeof(tong));cin>>n>>m;for(ll i=1;i<=n;i++){ll x; cin>>x;tong[x]++;}while(m--){ll op,x; cin>>op>>x;if(op==1) tong[x]++;else if(op==2) tong[x]--;else{for(ll i=0;i<=60;i++) r[i]=0;ll tmp=0;while(x) r[tmp++]=x&1,x>>=1;tmp=0;for(ll i=60;i>=0;i--) if(r[i]) r[i]=0,r[i+tmp]++,tmp++;ll ans=0,sum=0;suf[61]=1;for(ll i=60;i>=0;i--) suf[i]=suf[i+1]*C(r[i],tong[i])%P;for(ll i=0;i<=60;i++){ll a=qpow(2,sum);ll b=qpow(2,tong[i]);for(ll j=0;j<=r[i];j++){b=(b-C(j,tong[i])+P)%P;}ll c=suf[i+1];ans=(ans+a*b%P*c%P)%P;sum+=tong[i];}ll ans2=1;for(ll i=0;i<=60;i++) ans2=ans2*C(r[i],tong[i])%P;ans=(ans+ans2)%P;cout<<ans<<"\n";}}
}

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询