P8226樱点收集

P8266

分析题意可以打一个很显然的O(n2)暴力

丑陋的赛时代码 70pts

void work(){
    n=read(),m=read(),k=read();
    for(int i=1;i<=m;++i){
        int x=read();vis[x]=1;
    }
    for(int i=1;i<=n;++i){
        a[i]=read();
    }
    int res=0;
    for(int bomb=0;bomb<=n;++bomb){
        int numsakura=0,ans=0;
        for(int i=1;i<=n;++i){
            if(bomb==i)continue;
            if(numsakura+a[i]>k){
                numsakura=(numsakura+a[i])%k;
                if(numsakura==0 && vis[i]){
                   ans++;
                }
            }
            else if(numsakura+a[i]==k){
                numsakura=0;
                if(vis[i]){
                    ans++;
                }
            }
            else numsakura+=a[i];
        }
        res=max(res,ans);
    }
    printf("%d\n",res);
}
int main(){
    work();
	return 0;
}

接下来考虑动一下脑子

对于每一个关卡,只有在最后在收集完最后一个樱点结界展开时才对答案有贡献,所以我们只考虑恰好的时刻,忽略中间结界展开的过程。

先不考虑放bomb,维护一个前缀和sum,显然有当$ sum[i] \mod k ==0i,ansbombi$个关卡的贡献,则有

if(sum[i]%k==0){
	ans[i]=ans[i-1]+vis[i];
}
else ans[i]=ans[i-1];

接下来考虑放bomb,如果在位置j放了一个bomb1j1收集到的樱点还是对应的前缀和,也就是说对他们都没有影响,后面收集到的樱点为sum[i]a[j]。如果sum[i]a[j]modk==0才对答案有贡献,但是如果O(n2)再算一遍显然不现实。所以我们倒着搞

学过数论的选手都晓得sum[i]a[j]modk==0实际上为sum[i]a[j]modk,维护一个数组rest,下标为xmodk, rest[i]表示在i关卡之前放了一个bombi关卡对答案的贡献,则有

for(int i=n;i>0;--i){//枚举bomb
    res=max(res,ans[i-1]+rest[a[i]%k]);
    rest[sum[i]%k]+=vis[i];
}

然后就结束了

Speakisnothing,ShowmetheCode.

#include<bits/stdc++.h>
using namespace std;
inline 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;
}
const int maxn=3e5+5;
const int maxk=1e6+5;
int n,m,k;
int a[maxn];
int sum[maxn];
bool vis[maxn];
int rest[maxk];
int ans[maxn];
void work(){
    n=read(),m=read(),k=read();
    for(int i=1;i<=m;++i){
        int x=read();vis[x]=1;
    }
    for(int i=1;i<=n;++i){
        a[i]=read();
		sum[i]=sum[i-1]+a[i];
	}
    int res=0;
	for(int i=1;i<=n;++i){
		ans[i]=ans[i-1];
        if(sum[i]%k==0){
			ans[i]++;
		}
	}
	for(int i=n;i>0;--i){
		res=max(res,ans[i-1]+rest[a[i]%k]);
		rest[sum[i]%k]+=vis[i];
	}
    printf("%d\n",res);
}
int main(){
    work();
	return 0;
}
posted @   Chano_sb  阅读(41)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 全程不用写代码,我用AI程序员写了一个飞机大战
· DeepSeek 开源周回顾「GitHub 热点速览」
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 记一次.NET内存居高不下排查解决与启示
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
点击右上角即可分享
微信分享提示