Codeforces Round #775 (Div. 2) Solution Set
暂时只有 Div. 2。
CF1649A Game
显然要找到最长的前缀和后缀是 \(1\),然后中间跳过去。特判全是 \(1\) 的情况,不需要花费。
/*
他决定要“格”院子里的竹子。于是他搬了一条凳子坐在院子里,面对着竹子硬想了七天,结果因为头痛而宣告失败。
DONT NEVER AROUND . //
*/
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
char buf[1<<21],*p1=buf,*p2=buf;
#define getchar() (p1==p2 && (p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++)
int read()
{
int x=0;
char c=getchar();
while(c<'0' || c>'9') c=getchar();
while(c>='0' && c<='9') x=(x<<1)+(x<<3)+(c^'0'),c=getchar();
return x;
}
void write(int x)
{
if(x>9) write(x/10);
putchar(x%10+'0');
}
const int MOD=998244353;
inline int Add(int u,int v){return u+v>=MOD?u+v-MOD:u+v;}
inline int Sub(int u,int v){return u-v>=0?u-v:u-v+MOD;}
inline int Mul(int u,int v){return LL(u)*LL(v)%MOD;}
int QuickPow(int x,int p)
{
if(p<0) p+=MOD-1;
int ans=1,base=x;
while(p)
{
if(p&1) ans=Mul(ans,base);
base=Mul(base,base);
p>>=1;
}
return ans;
}
int a[105],n;
void Solve()
{
n=read();
int x=0;
for(int i=1;i<=n;++i) x+=(a[i]=read());
if(x==n)
{
puts("0");
return ;
}
int sum=n+1;
for(int i=1;i<=n;++i)
{
if(!a[i]) break;
--sum;
}
for(int i=n;i;--i)
{
if(!a[i]) break;
--sum;
}
write(sum),puts("");
}
int main(){
int T=read();
while(T-->0) Solve();
return 0;
}
CF1649B Game of Ball Passing
既然官方的 Sol 也声称在猜结论,那我也猜结论吧。
特判没传球的情况,然后考虑最大值 \(p\) 和总传球数 \(s\) 的关系。
如果 \(2p\leq s\),答案是 \(1\);否则最大值需要踢出去 \(2p-s\) 个球,答案也是 \(2p-s\)。
/*
他决定要“格”院子里的竹子。于是他搬了一条凳子坐在院子里,面对着竹子硬想了七天,结果因为头痛而宣告失败。
DONT NEVER AROUND . //
*/
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
char buf[1<<21],*p1=buf,*p2=buf;
#define getchar() (p1==p2 && (p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++)
LL read()
{
LL x=0;
char c=getchar();
while(c<'0' || c>'9') c=getchar();
while(c>='0' && c<='9') x=(x<<1)+(x<<3)+(c^'0'),c=getchar();
return x;
}
void write(LL x)
{
if(x>9) write(x/10);
putchar(x%10+'0');
}
LL a[100005],n;
void Solve()
{
n=read();
for(LL i=1;i<=n;++i) a[i]=read();
for(LL i=1;i<=n;++i) if(a[i]) goto fail;
puts("0");
return ;
fail:;
LL sum=0,maxn=0;
for(LL i=1;i<=n;++i) sum+=a[i],maxn=max(maxn,a[i]);
if(maxn*2<=sum) puts("1");
else write(maxn-(sum-maxn)),puts("");
}
int main(){
LL T=read();
while(T-->0) Solve();
return 0;
}
CF1648A Weird Sum
注意到每一维独立,分开算。
把每种颜色的某一维坐标摊开,求两两间距离。排序过后就是前缀和。
/*
他决定要“格”院子里的竹子。于是他搬了一条凳子坐在院子里,面对着竹子硬想了七天,结果因为头痛而宣告失败。
DONT NEVER AROUND . //
*/
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
char buf[1<<21],*p1=buf,*p2=buf;
#define getchar() (p1==p2 && (p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++)
LL read()
{
LL x=0;
char c=getchar();
while(c<'0' || c>'9') c=getchar();
while(c>='0' && c<='9') x=(x<<1)+(x<<3)+(c^'0'),c=getchar();
return x;
}
void write(LL x)
{
if(x>9) write(x/10);
putchar(x%10+'0');
}
vector<LL> C[100005][2];
LL n,m;
int main(){
n=read(),m=read();
for(LL i=1;i<=n;++i) for(LL j=1;j<=m;++j) {int c=read();C[c][0].push_back(i),C[c][1].push_back(j);}
for(LL i=1;i<=100000;++i) sort(C[i][0].begin(),C[i][0].end()),sort(C[i][1].begin(),C[i][1].end());
LL ans=0;
for(LL i=1;i<=100000;++i)
{
LL sum=0,cnt=0;
for(auto v:C[i][0]) ans+=cnt*v-sum,++cnt,sum+=v;
sum=0,cnt=0;
for(auto v:C[i][1]) ans+=cnt*v-sum,++cnt,sum+=v;
}
write(ans);
return 0;
}
CF1648B Integral Array
枚举 \(d=\left\lfloor \frac{x}{y} \right\rfloor\),将 \(a\) 去重,就可以 \(O(n \ln n)\) 暴力做了。
/*
他决定要“格”院子里的竹子。于是他搬了一条凳子坐在院子里,面对着竹子硬想了七天,结果因为头痛而宣告失败。
DONT NEVER AROUND . //
*/
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
char buf[1<<21],*p1=buf,*p2=buf;
#define getchar() (p1==p2 && (p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++)
int read()
{
int x=0;
char c=getchar();
while(c<'0' || c>'9') c=getchar();
while(c>='0' && c<='9') x=(x<<1)+(x<<3)+(c^'0'),c=getchar();
return x;
}
void write(int x)
{
if(x>9) write(x/10);
putchar(x%10+'0');
}
inline int lowbit(int x){return x&(-x);}
int n,c,a[1000005];
int sum[2000005];
void Solve()
{
n=read(),c=read();
for(int i=1;i<=n;++i) a[i]=read();
sort(a+1,a+1+n);
n=unique(a+1,a+1+n)-a-1;
for(int i=1;i<=2*c;++i) sum[i]=0;
for(int i=1;i<=n;++i) sum[a[i]]=1;
for(int i=1;i<=2*c;++i) sum[i]+=sum[i-1];
for(int i=1;i<=c;++i)
{
if(sum[i]==sum[i-1])
{
for(int j=1;j*i<=c;++j)
{
if(sum[j]==sum[j-1]) continue;
if(sum[j*(i+1)-1]^sum[i*j-1])
{
puts("No");
return ;
}
}
}
}
puts("Yes");
}
int main(){
int T=read();
while(T-->0) Solve();
return 0;
}
CF1648C Tyler and Strings
就纯粹傻逼 Samples & Pretests.
枚举两个字符串相同的前缀到哪儿,然后在这个位置填一个数 \(p\) 使得 \(p < t_i\),那么后面怎么填都是合法的;然后在这里填一个 \(q=t_i\),考虑下一个位置。
算答案的话,对于一个位置,先把所有 \(x \geq t_i\) 的填进没有填入的位置(不含当前位置)。选位置是组合数算,可重集计数要用线段树存一下值域算一下区间阶乘逆元积,用树状数组存某个值域区间里有多少数。小于 \(t_i\) 的数也是可重集计数。
然后有巨大多 Corner Case:
- 如果当前的所有数都小于 \(t_i\):算完滚蛋;
- 如果当前填不进一个等于 \(t_i\) 的数:滚蛋;
- 如果 \(n<m\),并且存在一种排列方式使得 \(s = \operatorname{pre}(t,|s|)\):答案加一(记得取模)。
就这样。傻逼题,数据还巨大多傻逼。纯粹傻逼。
/*
他决定要“格”院子里的竹子。于是他搬了一条凳子坐在院子里,面对着竹子硬想了七天,结果因为头痛而宣告失败。
DONT NEVER AROUND . //
*/
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
char buf[1<<21],*p1=buf,*p2=buf;
#define getchar() (p1==p2 && (p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++)
LL read()
{
LL x=0;
char c=getchar();
while(c<'0' || c>'9') c=getchar();
while(c>='0' && c<='9') x=(x<<1)+(x<<3)+(c^'0'),c=getchar();
return x;
}
void write(LL x)
{
if(x>9) write(x/10);
putchar(x%10+'0');
}
const LL MOD=998244353;
inline LL Add(LL u,LL v){return u+v>=MOD?u+v-MOD:u+v;}
inline LL Sub(LL u,LL v){return u-v>=0?u-v:u-v+MOD;}
inline LL Mul(LL u,LL v){return u*v%MOD;}
LL QuickPow(LL x,LL p=MOD-2)
{
if(p<0) p+=MOD-1;
LL ans=1,base=x;
while(p)
{
if(p&1) ans=Mul(ans,base);
base=Mul(base,base);
p>>=1;
}
return ans;
}
inline LL lowbit(LL x){return x&(-x);}
const LL UP=200000;
struct BIT{
LL tr[200005];
void clear(){for(LL i=0;i<=UP;++i) tr[i]=0;}
void modify(LL x,LL v){for(LL i=x;i<=UP;i+=lowbit(i)) tr[i]+=v;}
LL query(LL x){LL ret=0;for(LL i=x;i;i^=lowbit(i)) ret+=tr[i];return ret;}
LL query(LL l,LL r){if(l>r) return 0;return query(r)-query(l-1);}
}bit;
LL fac[200005],ifac[200005];
inline LL C(LL n,LL m){return m<0 || n<m?0:Mul(fac[n],Mul(ifac[m],ifac[n-m]));}
LL n,m,s[200005],t[200005],app[200005];
#define lc(x) (x<<1)
#define rc(x) (lc(x)|1)
#define Mm LL mid=(l+r)>>1
LL mpl[800005];
void push_up(LL now){mpl[now]=Mul(mpl[lc(now)],mpl[rc(now)]);}
void build(LL l,LL r,LL now)
{
if(l==r)
{
mpl[now]=ifac[app[l]];
return ;
}
Mm;
build(l,mid,lc(now)),build(mid+1,r,rc(now));
push_up(now);
}
void modify(LL l,LL r,LL now,LL x,LL v)
{
if(l==r)
{
mpl[now]=ifac[v];
return ;
}
Mm;
if(x<=mid) modify(l,mid,lc(now),x,v);
else modify(mid+1,r,rc(now),x,v);
push_up(now);
}
LL query(LL l,LL r,LL now,LL x,LL y)
{
if(x>y) return 0;
if(x<=l && r<=y) return mpl[now];
Mm,ret=1;
if(x<=mid) ret=Mul(ret,query(l,mid,lc(now),x,y));
if(mid<y) ret=Mul(ret,query(mid+1,r,rc(now),x,y));
return ret;
}
#undef lc
#undef rc
#undef Mm
int main(){
// freopen("C.in","r",stdin);
// freopen("C.out","w",stdout);
fac[0]=1;
for(LL i=1;i<=200000;++i) fac[i]=Mul(fac[i-1],i);
ifac[200000]=QuickPow(fac[200000]);
for(LL i=199999;~i;--i) ifac[i]=Mul(ifac[i+1],i+1);
n=read(),m=read();
for(LL i=1;i<=n;++i) s[i]=read();
for(LL i=1;i<=m;++i) t[i]=read();
sort(s+1,s+1+n);
for(LL i=1;i<=n;++i) bit.modify(s[i],1),++app[s[i]];
build(1,UP,1);
LL ans=0;
for(LL i=1;i<=min(n,m);++i)
{
LL all(bit.query(1,t[i]));
if(all)
{
LL st(bit.query(1,t[i]-1)),pp=bit.query(1,UP);
if(st==pp)
{
ans=Add(ans,Mul(fac[n-i+1],query(1,UP,1,1,UP)));
goto haha;
}
else
{
pp-=st;
ans=Add(ans,Mul(Mul(C(n-i,pp),Mul(fac[pp],query(1,UP,1,t[i],UP))),Mul(fac[st],query(1,UP,1,1,t[i]-1))));
if(all==st) goto haha;
--app[t[i]];
bit.modify(t[i],-1);
modify(1,UP,1,t[i],app[t[i]]);
}
}
else goto haha;
}
if(n<m) ans=Add(ans,1);
haha:;
write(ans);
return 0;
}
CF1648D Serious Business
定义 \(dp_i\) 为最终停在 \((2,i)\) 的最大值。那么答案就是枚举 \(i\),算 \((2,i) \to (3,i) \to (3,n)\) 的最大值。
如何算 \(dp_i\) 呢?对于一个区间 \([l,r]\) 里的 \(i\),我们可以从 \(l-1\) 走进来,也可以从某个 \(j \in [l,i]\) 走过来。
转移式子的话,第一种情况是:\(dp_i = dp_{l-1} + suf_{2,l} - suf_{2,i+1} - k\),第二种情况是 \(dp_i = pre_{1,j} + suf_{2,j} - suf_{2,i+1} - k\),其中 \(pre,suf\) 分别表示前缀/后缀,第一个数表示行号。可以提出共同的只跟 \(i\) 有关的 \(-suf_{2,i+1}\)。
第一种情况的话,我们将每个区间用左端点排序。这样相当于区间打 \(\max\) 的标记。求单点最大值,可以采用标记永久化。
第二种情况,左子树会影响右子树。每个结点转移类似,可以直接打标记。
看代码吧。
/*
他决定要“格”院子里的竹子。于是他搬了一条凳子坐在院子里,面对着竹子硬想了七天,结果因为头痛而宣告失败。
DONT NEVER AROUND . //
*/
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
char buf[1<<21],*p1=buf,*p2=buf;
#define getchar() (p1==p2 && (p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++)
LL read()
{
LL x=0,f=1;
char c=getchar();
while(c<'0' || c>'9') f=(c=='-'?-1:f),c=getchar();
while(c>='0' && c<='9') x=(x<<1)+(x<<3)+(c^'0'),c=getchar();
return x*f;
}
void write(LL x)
{
if(x<0) putchar('-'),x=-x;
if(x>9) write(x/10);
putchar(x%10+'0');
}
LL n,q,a[4][500005],sum1[500005],sum2[500005],sum3[500005];
#define lc(x) (x<<1)
#define rc(x) (lc(x)|1)
#define Mm LL mid=(l+r)>>1
LL tr[2000005],tag[2000005],maxn[2000005];
void build(LL l,LL r,LL now)
{
tr[now]=-1e18,tag[now]=1e18;
if(l==r) return void(maxn[now]=sum1[l]+sum2[l]);
Mm;
build(l,mid,lc(now)),build(mid+1,r,rc(now));
maxn[now]=max(maxn[lc(now)],maxn[rc(now)]);
}
inline void push_down(LL now){if(tag[now]!=1e18) tr[rc(now)]=max(tr[rc(now)],maxn[lc(now)]-tag[now]),tag[lc(now)]=min(tag[lc(now)],tag[now]),tag[rc(now)]=min(tag[rc(now)],tag[now]);}
void modify(LL l,LL r,LL now,LL x,LL y,LL v)
{
if(x<=l && r<=y)
{
tr[now]=max(tr[now],v);
return ;
}
push_down(now);
Mm;
if(x<=mid) modify(l,mid,lc(now),x,y,v);
if(mid<y) modify(mid+1,r,rc(now),x,y,v);
}
void modify(LL l,LL r,LL now,LL x,LL y,LL k,LL &mxn)
{
if(x<=l && r<=y)
{
tr[now]=max(tr[now],mxn-k);
tag[now]=min(tag[now],k);
mxn=max(mxn,maxn[now]);
return ;
}
push_down(now);
Mm;
if(x<=mid) modify(l,mid,lc(now),x,y,k,mxn);
if(mid<y) modify(mid+1,r,rc(now),x,y,k,mxn);
}
LL query(LL l,LL r,LL now,LL x)
{
if(l==r) return max(tr[now],maxn[now]-tag[now]);
push_down(now);
Mm,ret=tr[now];
if(x<=mid) ret=max(query(l,mid,lc(now),x),ret);
else ret=max(query(mid+1,r,rc(now),x),ret);
return ret;
}
#undef lc
#undef rc
#undef Mm
vector<pair<LL,LL>> G[500005];
#define mp make_pair
LL dp[500005];
int main(){
n=read(),q=read();
for(LL i=1;i<=3;++i) for(LL j=1;j<=n;++j) a[i][j]=read();
#define A a[1]
#define B a[2]
#define C a[3]
for(LL i=1;i<=n;++i) sum1[i]=sum1[i-1]+A[i];
for(LL i=n;i;--i) sum2[i]=sum2[i+1]+B[i];
for(LL i=n;i;--i) sum3[i]=sum3[i+1]+C[i];
#undef A
#undef B
#undef C
build(1,n,1);
for(LL i=1;i<=q;++i)
{
LL l=read(),r=read(),k=read();
G[l].push_back(mp(r,k));
}
dp[0]=-1e18;
LL L=0,ans=-1e18;
for(LL i=1;i<=n;++i)
{
while(L<i-1) ++L,dp[L]=query(1,n,1,L)-sum2[L+1],ans=max(ans,dp[L]+sum3[L]);
for(auto st:G[i])
{
LL r=st.first,w=st.second;
modify(1,n,1,i,r,dp[i-1]+sum2[i]-w);
LL mxn=-1e18;
modify(1,n,1,i,r,w,mxn);
}
}
while(L<=n-1) ++L,dp[L]=query(1,n,1,L)-sum2[L+1],ans=max(ans,dp[L]+sum3[L]);
write(ans);
return 0;
}