Unknown Mother-Goose
遇到这种题目就可以考虑bitset
下面介绍手写bitset,以神鱼的代码为例
#include<cstdio>
#include<iostream>
#include<cstring>
#define N 1000000003
#define reg register
using namespace std;
unsigned long long bs[(N>>6)+10];
unsigned long long tmp[65];
int n,m,s,l,ans;
inline int count(unsigned long long x){
reg int res = 0;
while(x){
res += x&1;
x >>= 1;
}
return res;
}
int main(){
scanf("%d%d",&n,&s);
m = (n>>6)+1;
//每一个ull有八个字节
//每个字节有八个bit
//相当于一个ull可以有64个二进制位
//所以我们用m个ull来模拟有n个二进制位的bitset
while(s--){
scanf("%d",&l);
if(l<64){ //两种情况判一下,保证加入的复杂度是 n/w
memset(tmp,0,sizeof(tmp));
for(reg int i=0;i<(l<<6);i+=l)
tmp[i>>6] |= 1ull<<(i&63); //加入的数比较小,开另一个数组,作为重复单元
//注释2
for(reg int i=0;i<=m;i+=l)
for(reg int j=0;j<l;++j)
bs[i+j] |= tmp[j];
}else{
for(reg int i=0;i<=n;i+=l)
bs[i>>6] |= 1ull<<(i&63);//注释1
}
}
--m;
if((n&63)!=63) bs[m] &= (1ull<<(n+1-(m<<6)))-1; //特判一下最后一块
bs[0] &= -2ull; //除去第 0 项
for(reg int i=0;i<=m;++i) ans += count(bs[i]&(bs[i]<<1)&(bs[i]<<2));//考虑每一块的连续的三个一
for(reg int i=1;i<=m;++i) ans += count(bs[i]&(bs[i-1]>>62)&((bs[i-1]>>63)|(bs[i]<<1)));//考虑两块相接处的三个一
printf("%d",ans);
return 0;
}
注释1:
首先
注释2:
tmp数组相当于是模拟了bs数组的低
这样复杂度就被优化了
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构