[75] (NOIP集训) NOIP2024 加赛 8
A.flandre
我的做法是,所有数离散化之后扔进桶里,去枚举选择
lbtl 指出可能存在最优答案是选择
和 lbtl 交涉后尝试构造一组相同元素只选后一半的数据
令
- 不选
:设为 - 选
:
构造一组
说白了就是相等的数排完序后越靠前贡献越大,如果你选了后几个数,在这些数都是正贡献的情况下肯定要选后面的,都是负贡献的情况下肯定是为了选前面的数,否则不如不选
因此这种做法是有严格的正确性的,可能只是比较麻烦
赛时因为方案算对了答案算错了挂了
#include<bits/stdc++.h>
using namespace std;
template<typename T>
inline void read(T&x){
x=0;char ch=getchar();int f=1;
while(!isdigit(ch)){
if(ch=='-') f*=-1;
ch=getchar();
}
while(isdigit(ch)) x=x*10+ch-'0',ch=getchar();
x*=f;
}
#define int long long
int n,k;
int a[1000001];
int b[1000001];
int sum[1000001];
int sumcnt[1000001];
int sumnew[1000001];
int cnt[1000001];
vector<int>pos[1000001];
signed main(){
read(n);read(k);
for(int i=1;i<=n;++i){
read(a[i]);
b[i]=a[i];
}
sort(b+1,b+n+1);
int tmp=unique(b+1,b+n+1)-b-1;
for(int i=1;i<=n;++i){
a[i]=lower_bound(b+1,b+tmp+1,a[i])-b;
cnt[a[i]]++;
pos[a[i]].push_back(i);
}
for(int i=1;i<=tmp;++i){
sumcnt[i]=sumcnt[i-1]+cnt[i];
sum[i]=sum[i-1]+b[i]*cnt[i];
sumnew[i]=sumnew[i-1]+cnt[i]*(sumcnt[i-1]);
}
int ans=-0x7fffffffffffffff,anscnt=1;
for(int i=1;i<=tmp;++i){
if(sum[tmp]-sum[i-1]+k*(sumnew[tmp]-sumnew[i]-(tmp-i)*sumcnt[i-1])>ans){
ans=sum[tmp]-sum[i-1]+k*(sumnew[tmp]-sumnew[i]-(tmp-i)*sumcnt[i-1]);
anscnt=i;
}
}
if(ans<0){
printf("0 0");
return 0;
}
int tot=0,anss=0;
for(int i=anscnt;i<=tmp;++i){
for(int j:pos[i]){
anss+=b[a[j]]+tot*k;
}
tot+=(int)pos[i].size();
}
printf("%lld %lld\n",anss,tot);
for(int i=anscnt;i<=tmp;++i){
for(int j:pos[i]) printf("%lld ",j);
}
}
B.meirin
赛时偶遇
正确的解法应该是拆贡献,考虑到你把上面这坨东西拆开一定是一个形如
一种比较直观的方法是将原式改成
考虑求出这个玩意以后有什么用,如果你求出这东西,那么对
剩下的工作就是降这个预处理
#include<bits/stdc++.h>
using namespace std;
#define int long long
const int p=1e9+7;
int n,q;
int a[500001],b[500001];
int x[500001],y[500002],s[500001];
int qz[500001],hz[500002];
int sums[500001];
signed main(){
ios::sync_with_stdio(false);
cin>>n>>q;
for(int i=1;i<=n;++i){
cin>>a[i];
}
for(int i=1;i<=n;++i){
cin>>b[i];
}
for(int i=1;i<=n;++i){
qz[i]=(qz[i-1]+i*a[i]+p)%p;
hz[i]=(hz[i-1]+(n-i+1)*a[i]+p)%p;
}
for(int i=1;i<=n;++i){
x[i]=qz[i]%p;
y[i]=((hz[n]-hz[i-1]+p)%p+p)%p;
}
int ans=0;
for(int i=1;i<=n;++i){
s[i]=(s[i-1]-x[i-1]+y[i]+p)%p;
ans=(ans+b[i]*s[i])%p;
sums[i]=(sums[i-1]+s[i])%p;
}
while(q--){
int l,r,v;
cin>>l>>r>>v;
ans=((ans+(sums[r]-sums[l-1])*v%p)%p+p)%p;
cout<<ans<<'\n';
}
}
C.sakuya
发现期望是个诈骗东西,每两个节点相邻概率一样,题目实际上让求的是
对上面这个东西不难想到,对标记节点重构一棵树,直接跑换根就能得到答案
然而这个题带修,因此需要一些智慧的处理
因为是单点修改,想到可以把每个边的贡献下放到两端节点处,这和上个题就一样了,设
这个
#include<bits/stdc++.h>
using namespace std;
#define int long long
const int p=998244353;
int n,m;
struct edge{
int to,w;
};
vector<edge>e[500001];
bool vis[500001];
int viscnt[500001];
int f[500001];
int fa[500001];
inline int cal(int x,int y){ //find the ans of (x,y)
if(x==fa[y]) return viscnt[y]*(m-viscnt[y]);
else if(y==fa[x]) return viscnt[x]*(m-viscnt[x]);
assert(0);
}
void dfs1(int now,int last){
if(vis[now]) viscnt[now]=1;
else viscnt[now]=0;
fa[now]=last;
for(edge i:e[now]){
if(i.to!=last){
dfs1(i.to,now);
viscnt[now]+=viscnt[i.to];
}
}
}
int ans=0;
void dfs2(int now){
for(edge i:e[now]){
f[now]=(f[now]+cal(i.to,now))%p;
if(i.to!=fa[now]){
dfs2(i.to);
ans=(ans+i.w*cal(i.to,now))%p;
}
}
}
int power(int a,int t){
int base=a,ans=1;
while(t){
if(t&1){
ans=ans*base%p;
}
base=base*base%p;
t>>=1;
}
return ans;
}
signed main(){
ios::sync_with_stdio(false);
cin>>n>>m;
for(int i=1;i<=n-1;++i){
int x,y,z;
cin>>x>>y>>z;
e[x].push_back({y,z});
e[y].push_back({x,z});
}
int inv=power(m,p-2);
for(int i=1;i<=m;++i){
int x;cin>>x;
vis[x]=true;
}
dfs1(1,0);
dfs2(1);
int q;cin>>q;
while(q--){
int x,k;
cin>>x>>k;
ans=(ans+f[x]*k%p+p)%p;
cout<<ans*2*inv%p<<'\n';
}
}
something
也需要迎来故事的终局了
希望一切都会好起来
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!