ARC169
[ARC169A] Please Sign#
每个点会一直一直给它的父节点加,所以深度越深的点影响越大,统计出每个深度的点权和,从深到浅判断正负,有正负就输出答案,全都没有就是
#include<bits/stdc++.h>
using namespace std;
#define int long long
#define il inline
#define re register
const int N=3e5+10;
int n,a[N],dep[N],sum[N];
il int read(){
re int x=0;re char c=getchar(),f=0;
while(c<'0'||c>'9') f|=(c=='-'),c=getchar();
while(c>='0'&&c<='9') x=(x<<3)+(x<<1)+(c&15),c=getchar();
return f?-x:x;
}
signed main(){
n=read();
for(re int i=1;i<=n;i++)a[i]=read();
sum[0]=a[1];
for(re int i=2;i<=n;i++)
sum[dep[i]=dep[read()]+1]+=a[i];
for(re int i=n;i>=0;i--)
if(sum[i])return putchar(sum[i]>0?'+':'-'),0;
putchar('0');
return 0;
}
[ARC169B] Subsegments with Small Sums#
想起了 ARC060E。考虑倍增。
然后套一个
发现倍增没有用,还会算重,所以换回初始的东西,就是预处理出
对于每一组
我也很震惊竟然直接就过了,开心。
#include<bits/stdc++.h>
using namespace std;
#define int long long
#define il inline
#define re register
const int N=3e5+10;
int n,S,a[N],nxt[N],f[N],s[N],ans;
il int read(){
re int x=0;re char c=getchar(),f=0;
while(c<'0'||c>'9') f|=(c=='-'),c=getchar();
while(c>='0'&&c<='9') x=(x<<3)+(x<<1)+(c&15),c=getchar();
return f?-x:x;
}
signed main(){
// freopen("my.in","r",stdin);
// freopen("my.out","w",stdout);
n=read(),S=read();
for(re int i=1;i<=n;i++)a[i]=read(),s[i]=s[i-1]+a[i];
for(re int i=1;i<=n;i++)
nxt[i]=upper_bound(s+1,s+1+n,s[i-1]+S)-s-1;
for(re int i=0;i<n;i++)f[i]=1;
for(re int i=1;i<=n;i++){
ans+=(n-i+1)*f[i-1];
f[nxt[i]]+=f[i-1];
}
cout<<ans;
return 0;
}
[ARC169C] Not So Consecutive#
像一般的线性
考虑按连续段转移,设
枚举连续段的起点
转移就比较简单:
把
#include<bits/stdc++.h>
using namespace std;
#define int long long
#define il inline
#define re register
const int N=5010,mod=998244353;
int n,a[N],pos[N],f[N][N],s[N][N],S[N];
il int read(){
re int x=0;re char c=getchar(),f=0;
while(c<'0'||c>'9') f|=(c=='-'),c=getchar();
while(c>='0'&&c<='9') x=(x<<3)+(x<<1)+(c&15),c=getchar();
return f?-x:x;
}
signed main(){
// freopen("my.in","r",stdin);
// freopen("my.out","w",stdout);
n=read();
for(re int i=1;i<=n;i++)a[i]=read();
f[0][0]=S[0]=1;
for(re int i=1;i<=n;i++){
if(a[i]!=-1)pos[a[i]]=i;
int mx1=0,mx2=0;
for(re int j=1;j<=n;j++)
if(pos[j]>mx1)mx2=mx1,mx1=pos[j];
else mx2=max(mx2,pos[j]);
for(re int j=1;j<=n;j++){
int lst=max(i-j,(a[mx1]==j)?mx2:mx1);
f[i][j]=(S[i-1]-(lst?S[lst-1]:0)+mod-(s[i-1][j]-(lst?s[lst-1][j]:0)+mod)+mod)%mod;
s[i][j]=(s[i-1][j]+f[i][j])%mod,S[i]+=f[i][j];
}
S[i]=(S[i]+S[i-1])%mod;
}
cout<<(S[n]-S[n-1]+mod)%mod;
return 0;
}
[ARC169D] Add to Make a Permutation#
很符合我对做思维题的感觉的期望。
显然这些操作就是每次选
-
; -
之后两两不相同; -
令
, ; -
令
, 。
考虑第四个条件,当操作数一定时,
结论:若有解,那么一定存在一种最优解形如
用调整法证明。假设我们得到了一个最优解
-
, ; -
加减
不影响 之后的结果; -
加减
之后 不变,又因为答案只与 有关,所以答案不变,仍然最优; -
, 。
综上,调整之后的序列仍然合法。
那么考虑计算最优解,即最小化
第一个条件为
再看第四个条件,
最后只需要满足第三个条件就好了,发现
#include<bits/stdc++.h>
using namespace std;
#define int long long
#define il inline
#define re register
const int N=3e5+10;
int n,m,a[N],x,sum,mx;
il int read(){
re int x=0;re char c=getchar(),f=0;
while(c<'0'||c>'9') f|=(c=='-'),c=getchar();
while(c>='0'&&c<='9') x=(x<<3)+(x<<1)+(c&15),c=getchar();
return f?-x:x;
}
signed main(){
n=read(),m=read();
for(re int i=0;i<n;i++)a[i]=read();
sort(a,a+n);
for(re int i=0;i<n;i++)x=max(x,a[i]-i);
for(re int i=0;i<n;i++)sum+=x+i-a[i];
bool flg=0;
for(re int i=0;i<m;i++)
if(!((sum+n*i)%m)){
flg=1,x+=i,sum+=n*i;
break;
}
if(!flg)return puts("-1"),0;
for(re int i=0;i<n;i++)mx=max(mx,x+i-a[i]);
while(mx>sum/m)mx+=m/__gcd(n,m),sum+=n*m/__gcd(n,m);
cout<<sum/m;
return 0;
}
[ARC169E] Avoid Boring Matches#
先判无解,R
比 B
多显然无解,否则排成 BBB...RRR
一定有解。
考虑每轮匹配的最优策略,我们首先保证留下尽量多的 B
,其次保证留下的这些 B
的位置尽量靠前。那么我们从左往右考虑每一个 B
,将它与它后面第一个 R
匹配,最后再把没有匹配的随便匹配。
考虑一个合法串“至少”应该是怎样,即找到一个“合法的最低标准”,那么我们考虑在构造合法解的同时让 B
的数量尽量少(刚好一半),并且位置尽量靠后。
设
考虑怎样由 R
说明没有匹配,就在 R
;如果为 B
,那么我们要使得下一个 B
尽量靠后,就要在此处多放一个 R
直接与它配对,这样就可以多占一个位置,使得下一个 B
尽量靠后,即在 BR
。
然后考虑怎样让 B
的位置为
于是就得到了最少
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define il inline
#define re register
const int N=19;
string s,t[N];
int n,tot,pos[1<<N];
ll ans;
il int read(){
re int x=0;re char c=getchar(),f=0;
while(c<'0'||c>'9') f|=(c=='-'),c=getchar();
while(c>='0'&&c<='9') x=(x<<3)+(x<<1)+(c&15),c=getchar();
return f?-x:x;
}
int main(){
n=read(),getline(cin,s);
t[0]="R";
for(re int i=1;i<=n;i++){
for(char c:t[i-1])
if(c=='R')t[i]+='R';
else t[i]+="BR";
int d=(1<<i)-t[i].size();
while(d--)t[i]+='B';
}
for(re int i=0;i<(1<<n);i++)
if(t[n][i]=='B')pos[++tot]=i;
tot=0;
for(re int i=0;i<(1<<n);i++)
if(s[i]=='B'){
ans+=max(0,i-pos[++tot]);
if(tot==(1<<n-1))break;
}
if(tot^(1<<n-1))puts("-1");
else cout<<ans;
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!