【做题记录】2025刷题计划--根号算法
A. Tree Master
考虑根号分治,暴力处理。对于一层,设点数为 \(cnt\)。
- 若 \(cnt>\sqrt{n}\),这样的层最多有 \(\sqrt{n}\) 层,每一层最多计算 \(q\) 次,时间复杂度为 \(O(q\sqrt{n})\)。
- 否则 \(cnt\le\sqrt{n}\),进行记忆化,每一层最多计算 \(cnt\choose 2\) 次,最多有 \(\frac{n}{cnt}\) 层,时间复杂度就是 \(O(n\sqrt{n})\) 的。
于是可以通过。空间复杂度 \(O(n\sqrt{n})\)。
Code
复制代码
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
using namespace std;
namespace asbt{
namespace cplx{bool begin;}
const int maxn=1e5+5;
int n,m,fa[maxn],cnt[maxn];
int dep[maxn],bfn[maxn],blen;
ll a[maxn],**mem[maxn];
vector<int> e[maxn],cun[maxn];
queue<int> q;
il ll dfs(int u,int v){
if(!u&&!v){
return 0;
}
if(cnt[dep[u]]<=blen&&~mem[dep[u]][bfn[u]][bfn[v]]){
return mem[dep[u]][bfn[u]][bfn[v]];
}
ll res=a[u]*a[v]+dfs(fa[u],fa[v]);
if(cnt[dep[u]]<=blen){
mem[dep[u]][bfn[u]][bfn[v]]=mem[dep[u]][bfn[v]][bfn[u]]=res;
}
return res;
}
namespace cplx{
bool end;
il double usdmem(){return (&begin-&end)/1048576.0;}
}
int main(){
ios::sync_with_stdio(0),cin.tie(0);
cin>>n>>m;
for(int i=1;i<=n;i++){
cin>>a[i];
}
for(int i=2;i<=n;i++){
cin>>fa[i];
e[fa[i]].pb(i);
}
blen=sqrt(n);
q.push(1);
while(q.size()){
int u=q.front();
q.pop();
dep[u]=dep[fa[u]]+1;
bfn[u]=cnt[dep[u]];
cun[dep[u]].pb(u);
cnt[dep[u]]++;
for(int v:e[u]){
q.push(v);
}
}
for(int i=1;i<=n;i++){
if(cnt[i]<=blen){
mem[i]=new ll*[cnt[i]]();
for(int j=0;j<cnt[i];j++){
mem[i][j]=new ll[cnt[i]]();
for(int k=0;k<cnt[i];k++){
mem[i][j][k]=-1;
}
}
}
}
while(m--){
int u,v;
cin>>u>>v;
cout<<dfs(u,v)<<"\n";
}
for(int i=1;i<=n;i++){
if(cnt[i]<=blen){
for(int j=0;j<cnt[i];j++){
delete[] mem[i][j];
}
delete[] mem[i];
}
}
return 0;
}
}
int main(){return asbt::main();}
B. [COTS/CETS 2024] 双双决斗 Dvoboj
考虑如果没有修改,用 ST 表就非常舒服。
考虑暴力修改,需要修改所有覆盖了这个位置的区间,时间复杂度是 \(O(n)\) 的。
而如果只修改 \(\frac{\log n}{2}\) 层,时间复杂度就是 \(O(\sqrt{n})\) 的。查询时从上往下查,最多查到第 \(\frac{\log n}{2}\) 层,时间复杂度就也是 \(O(\sqrt{n})\) 的。于是就可以通过。
Code
复制代码
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
using namespace std;
namespace asbt{
namespace cplx{bool begin;}
const int maxn=2e5+5;
int n,m,blen,st[maxn][20];
il int Log(int x){
if(x==1){
return 0;
}
return Log(x>>1)+1;
}
il void upd(int l,int k){
if(k==blen){
return ;
}
if(l-(1<<k)>0){
st[l-(1<<k)][k+1]=abs(st[l-(1<<k)][k]-st[l][k]);
upd(l-(1<<k),k+1);
}
if(l+(1<<(k+1))-1<=n){
st[l][k+1]=abs(st[l][k]-st[l+(1<<k)][k]);
upd(l,k+1);
}
}
il int query(int l,int k){
if(k<=blen){
return st[l][k];
}
return abs(query(l,k-1)-query(l+(1<<(k-1)),k-1));
}
namespace cplx{
bool end;
il double usdmem(){return (&begin-&end)/1048576.0;}
}
int main(){
ios::sync_with_stdio(0),cin.tie(0);
cin>>n>>m;
for(int i=1;i<=n;i++){
cin>>st[i][0];
}
blen=Log(n)>>1;
for(int j=1;j<=blen;j++){
for(int i=1;i+(1<<j)-1<=n;i++){
st[i][j]=abs(st[i][j-1]-st[i+(1<<(j-1))][j-1]);
}
}
while(m--){
int opt,l,k;
cin>>opt>>l>>k;
if(opt==1){
st[l][0]=k;
upd(l,0);
}
else{
cout<<query(l,k)<<"\n";
}
}
return 0;
}
}
int main(){return asbt::main();}
C. 「SMOI-R1」Apple
考虑没有修改,高位前缀和就很舒服。如果修改就需要同时修改所有超集,时间复杂度是 \(O(2^n)\) 的。
考虑将一个二进制数拆成前后两段,修改时上传一段,查询时下查另一段,时间复杂度就是 \(O(q2^{\frac{n}{2}})\) 的。
Code
复制代码
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
- 87
- 88
- 89
- 90
- 91
- 92
- 93
- 94
- 95
- 96
- 97
- 98
- 99
- 100
- 101
- 102
- 103
- 104
- 105
- 106
- 107
- 108
- 109
- 110
using namespace std;
namespace asbt{
namespace cplx{bool begin;}
namespace IO{
const int bufsz=1<<20;
char ibuf[bufsz],*p1=ibuf,*p2=ibuf;
il int read(){
char ch=getchar();
while(ch<'0'||ch>'9'){
ch=getchar();
}
int x=0;
while(ch>='0'&&ch<='9'){
x=(x<<1)+(x<<3)+(ch^48);
ch=getchar();
}
return x;
}
char obuf[bufsz],*p3=obuf,s[50];
il void write(int x,bool typ=1){
int top=0;
do{
s[++top]=x%10|48;
x/=10;
}while(x);
while(top){
putchar(s[top--]);
}
putchar(typ?'\n':' ');
}
class Flush{
public:
~Flush(){
flush();
}
}FL;
}
using IO::read;
using IO::write;
const int maxn=(1<<10)+5,maxm=(1<<20)+5;
int n,m,blen,bsan,b[maxm];
int qan[maxm],hou[maxm];
int a[maxn][maxn];
il void upd(int p,int v){
for(int i=hou[p];;i=(i+1)|hou[p]){
a[qan[p]][i]+=v;
if(i==bsan){
return ;
}
}
}
il int query(int p){
int res=0;
for(int i=qan[p];;i=(i-1)&qan[p]){
res+=a[i][hou[p]];
if(!i){
return res;
}
}
}
namespace cplx{
bool end;
il double usdmem(){return (&begin-&end)/1048576.0;}
}
signed main(){
ios::sync_with_stdio(0),cin.tie(0);
cin>>n>>m;
blen=n>>1;
bsan=(1<<blen)-1;
for(int i=0;i<1<<n;i++){
cin>>b[i];
qan[i]=i>>blen;
hou[i]=i&bsan;
upd(i,b[i]);
}
while(m--){
int opt,p;
cin>>opt>>p;
if(opt==1){
cout<<query(p)<<"\n";
}
else{
int v;
cin>>v;
upd(p,v-b[p]);
b[p]=v;
}
}
return 0;
}
}
signed main(){return asbt::main();}
/*
3 5
0 1 2 3 4 5 6 7
2 1 2
2 2 3
2 3 4
2 6 10
1 7
*/
D. Till I Collapse
考虑当确定了 \(k\) 时,可以 \(O(n)\) 贪心去扫。
显然 \(k\) 递增时答案是不增的,同时答案小于 \(\frac{n}{k}\),所以不同的答案只有 \(O(\sqrt{n})\) 种。
于是对于 \(k<\sqrt{n}\) 暴力扫,对于 \(k\ge\sqrt{n}\) 暴力扫后二分有哪些 \(k\) 的答案是当前这个值。时间复杂度 \(O(n\sqrt{n}\log{n})\)。
Code
复制代码
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
- 87
- 88
- 89
- 90
- 91
- 92
- 93
using namespace std;
namespace asbt{
namespace cplx{bool begin;}
const int maxn=1e5+5;
int n,a[maxn],blen,buc[maxn];
namespace cplx{
bool end;
il double usdmem(){return (&begin-&end)/1048576.0;}
}
int main(){
// ios::sync_with_stdio(0),cin.tie(0);
cin>>n;
for(int i=1;i<=n;i++){
cin>>a[i];
}
blen=sqrt(n);
for(int i=1,ans;i<=blen;i++){
ans=1;
for(int j=1;j<=n;j++){
buc[j]=0;
}
for(int j=1,p=1,num=0;j<=n;j++){
if(buc[a[j]]++==0){
num++;
}
if(num>i){
ans++;
for(int k=p;k<j;k++){
buc[a[k]]--;
}
num=1,p=j;
}
}
cout<<ans<<" ";
}
// puts("666");
for(int i=blen+1,ans,l,r;i<=n;i++){
// cout<<i<<"\n";
ans=1;
for(int j=1;j<=n;j++){
buc[j]=0;
}
for(int j=1,p=1,num=0;j<=n;j++){
if(buc[a[j]]++==0){
num++;
}
if(num>i){
ans++;
for(int k=p;k<j;k++){
buc[a[k]]--;
}
num=1,p=j;
}
}
// cout<<i<<" "<<ans<<"\n";
l=i,r=n;
while(l<r){
int mid=(l+r+1)>>1,res=1;
for(int j=1;j<=n;j++){
buc[j]=0;
}
for(int j=1,p=1,num=0;j<=n;j++){
if(buc[a[j]]++==0){
num++;
}
if(num>mid){
res++;
for(int k=p;k<j;k++){
buc[a[k]]--;
}
num=1,p=j;
}
}
if(res==ans){
l=mid;
}
else{
r=mid-1;
}
}
// cout<<i<<" "<<l<<"\n";
for(int j=i;j<=l;j++){
cout<<ans<<" ";
}
i=l;
}
return 0;
}
}
int main(){return asbt::main();}
E. Mr
根号分治,对于包含的边数 \(\le\sqrt{m}\) 的颜色暴力枚举所有点对存入 map
,对于大于 \(\sqrt{m}\) 的颜色暴力扫所有查询。时间复杂度 \(O(m\sqrt{m}\log{m})\)。
Code
复制代码
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
- 87
- 88
- 89
- 90
- 91
- 92
- 93
- 94
- 95
- 96
- 97
- 98
- 99
- 100
- 101
- 102
- 103
- 104
- 105
- 106
- 107
- 108
- 109
- 110
- 111
- 112
- 113
- 114
- 115
- 116
- 117
- 118
- 119
- 120
- 121
- 122
- 123
- 124
- 125
- 126
- 127
- 128
- 129
- 130
- 131
- 132
- 133
- 134
- 135
- 136
- 137
using namespace std;
namespace asbt{
namespace cplx{bool begin;}
namespace IO{
const int bufsz=1<<20;
char ibuf[bufsz],*p1=ibuf,*p2=ibuf;
il int read(){
char ch=getchar();
while(ch<'0'||ch>'9'){
ch=getchar();
}
int x=0;
while(ch>='0'&&ch<='9'){
x=(x<<1)+(x<<3)+(ch^48);
ch=getchar();
}
return x;
}
char obuf[bufsz],*p3=obuf,s[50];
il void write(int x){
int top=0;
do{
s[++top]=x%10|48;
x/=10;
}while(x);
while(top){
putchar(s[top--]);
}
putchar('\n');
}
class Flush{
public:
~Flush(){
flush();
}
}FL;
}
using IO::read;
using IO::write;
const int maxn=1e5+5;
int n,m,q,blen,ans[maxn];
int fa[maxn],sz[maxn],cun[maxn<<1];
pii wt[maxn];
vector<pii> e[maxn];
map<pii,int> wth;
il int find(int x){
return x!=fa[x]?fa[x]=find(fa[x]):x;
}
il void merge(int u,int v){
u=find(u),v=find(v);
if(u==v){
return ;
}
if(sz[u]<sz[v]){
swap(u,v);
}
sz[u]+=sz[v],fa[v]=u;
}
namespace cplx{
bool end;
il double usdmem(){return (&begin-&end)/1048576.0;}
}
int main(){
n=read(),m=read();
// puts("666");
blen=sqrt(m);
for(int i=1,u,v,w;i<=m;i++){
u=read(),v=read(),w=read();
e[w].pb(mp(u,v));
}
// puts("666");
q=read();
for(int i=1,u,v;i<=q;i++){
u=read(),v=read();
if(u>v){
swap(u,v);
}
wt[i]=mp(u,v);
}
for(int i=1;i<=n;i++){
fa[i]=i,sz[i]=1;
}
for(int i=1,tot;i<=m;i++){
if(!e[i].size()){
continue;
}
tot=0;
for(pii j:e[i]){
merge(j.fir,j.sec);
cun[++tot]=j.fir;
cun[++tot]=j.sec;
}
sort(cun+1,cun+tot+1);
tot=unique(cun+1,cun+tot+1)-cun-1;
if(e[i].size()>blen){
for(int j=1;j<=q;j++){
if(find(wt[j].fir)==find(wt[j].sec)){
ans[j]++;
}
}
}
else{
for(int j=1;j<=tot;j++){
for(int k=j+1;k<=tot;k++){
if(find(cun[j])==find(cun[k])){
wth[mp(cun[j],cun[k])]++;
}
}
}
}
for(int j=1;j<=tot;j++){
fa[cun[j]]=cun[j];
sz[cun[j]]=1;
}
}
// puts("666");
for(int i=1;i<=q;i++){
write(ans[i]+wth[mp(wt[i].fir,wt[i].sec)]);
}
return 0;
}
}
int main(){return asbt::main();}
F. ycz的妹子
用线段树维护区间颜值和与妹子个数即可。时间复杂度 \(O(m\log{n})\)。
Code
复制代码
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
- 87
- 88
- 89
- 90
- 91
- 92
- 93
- 94
- 95
- 96
- 97
- 98
- 99
- 100
- 101
- 102
- 103
- 104
- 105
- 106
- 107
- 108
- 109
- 110
- 111
- 112
using namespace std;
namespace asbt{
namespace cplx{bool begin;}
const int maxn=5e5+5;
int n,m,a[maxn];
int sum[maxn<<2],sz[maxn<<2];
il void pushup(int id){
sum[id]=sum[lid]+sum[rid];
sz[id]=sz[lid]+sz[rid];
}
il void build(int id,int l,int r){
if(l==r){
if(l<=n){
sum[id]=a[l],sz[id]=1;
}
return ;
}
int mid=(l+r)>>1;
build(lid,l,mid);
build(rid,mid+1,r);
pushup(id);
}
il void upd1(int id,int l,int r,int p,int v){
if(l==r){
sum[id]-=v;
return ;
}
int mid=(l+r)>>1;
if(p<=mid){
upd1(lid,l,mid,p,v);
}
else{
upd1(rid,mid+1,r,p,v);
}
pushup(id);
}
il void upd2(int id,int l,int r,int p,int v){
if(l==r){
sum[id]=v,sz[id]=1;
return ;
}
int mid=(l+r)>>1;
if(p<=mid){
upd2(lid,l,mid,p,v);
}
else{
upd2(rid,mid+1,r,p,v);
}
pushup(id);
}
il void upd3(int id,int l,int r,int p){
if(l==r){
sum[id]=sz[id]=0;
return ;
}
int mid=(l+r)>>1;
if(sz[lid]>=p){
upd3(lid,l,mid,p);
}
else{
upd3(rid,mid+1,r,p-sz[lid]);
}
pushup(id);
}
namespace cplx{
bool end;
il double usdmem(){return (&begin-&end)/1048576.0;}
}
signed main(){
ios::sync_with_stdio(0),cin.tie(0);
cin>>n>>m;
for(int i=1;i<=n;i++){
cin>>a[i];
}
build(1,1,5e5);
while(m--){
char opt;
cin>>opt;
switch(opt){
case 'C':{
int p,v;
cin>>p>>v;
upd1(1,1,5e5,p,v);
break;
}
case 'I':{
int p,v;
cin>>p>>v;
upd2(1,1,5e5,p,v);
break;
}
case 'D':{
int p;
cin>>p;
upd3(1,1,5e5,p);
break;
}
default:{
cout<<sum[1]<<"\n";
break;
}
}
}
return 0;
}
}
signed main(){return asbt::main();}
G. Robin Hood Archery
考虑两个人的最优策略,一定都是先射击分高的。因此后手不可能赢,要求不输只能 \([l,r]\) 内每个分数都出现偶数次,才能平局。异或哈希即可。时间复杂度 \(O(n)\)。
Code
复制代码
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
using namespace std;
namespace asbt{
namespace cplx{bool begin;}
const int maxn=1e6+5;
int T,n,m,a[maxn];
ull ha1[maxn],ha2[maxn];
ull hs1[maxn],hs2[maxn];
mt19937_64 rdsd(time(0));
namespace cplx{
bool end;
il double usdmem(){return (&begin-&end)/1048576.0;}
}
int main(){
ios::sync_with_stdio(0),cin.tie(0);
for(int i=1;i<=1e6;i++){
while(!ha1[i]){
ha1[i]=rdsd();
}
while(!ha2[i]){
ha2[i]=rdsd();
}
}
cin>>T;
while(T--){
cin>>n>>m;
for(int i=1;i<=n;i++){
cin>>a[i];
hs1[i]=hs1[i-1]^ha1[a[i]];
hs2[i]=hs2[i-1]^ha2[a[i]];
}
while(m--){
int l,r;
cin>>l>>r;
puts(hs1[r]==hs1[l-1]&&hs2[r]==hs2[l-1]?"YES":"NO");
}
}
return 0;
}
}
int main(){return asbt::main();}
H. [THUPC 2017] 钦妹的玩具商店
分块,设块长为 \(B\),预处理 \(f_{l,r,x}\) 表示仅考虑 \([1,l]\cup[r,\frac{n}{B}]\) 中的玩具,花 \(x\) 元的最大愉悦度。询问时向 \(f_{bel_l-1,bel_r+1}\) 中加入 \(l\) 和 \(r\) 所在块内的玩具即可。\(bel_l\) 表示 \(l\) 所在块。
使用二进制优化多重背包,分析时间复杂度:
- 预处理 \(O(\frac{n^2m\log{n}}{B})\)
- 询问 \(O(qmB\log{n})\)
令 \(B=\sqrt{n}\),时间复杂度为 \(O((n+q)m\sqrt{n}\log{n})\),空间复杂度 \(O(nm)\)。
Code
复制代码
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
- 87
- 88
- 89
- 90
- 91
- 92
- 93
- 94
- 95
- 96
- 97
- 98
- 99
- 100
- 101
- 102
- 103
- 104
- 105
- 106
- 107
- 108
- 109
- 110
using namespace std;
namespace asbt{
namespace cplx{bool begin;}
const int maxn=1e3+5,maxm=40,mod=1e8+7;
int T,n,m,q,blen,bnum;
int a[maxn],b[maxn],c[maxn];
int bel[maxn],st[maxm],ed[maxm];
struct DP{
int f[maxn];
il void init(){
for(int i=0;i<=m;i++){
f[i]=0;
}
}
il int operator[](int x){
return f[x];
}
il void upd(int x){
int a=asbt::a[x],b=asbt::b[x],c=asbt::c[x];
for(int i=1;i<=c;i<<=1){
for(int j=m;j>=i*a;j--){
f[j]=max(f[j],f[j-i*a]+i*b);
}
c-=i;
}
for(int i=m;i>=c*a;i--){
f[i]=max(f[i],f[i-c*a]+c*b);
}
}
}dp[maxm][maxm];
il void solve(){
cin>>n>>m>>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++){
cin>>c[i];
}
blen=sqrt(n);
bnum=(n+blen-1)/blen;
for(int i=1;i<=bnum;i++){
st[i]=ed[i-1]+1;
ed[i]=min(ed[i-1]+blen,n);
for(int j=st[i];j<=ed[i];j++){
bel[j]=i;
}
}
for(int i=0;i<=bnum;i++){
if(!i){
dp[i][bnum+1].init();
}
else{
dp[i][bnum+1]=dp[i-1][bnum+1];
for(int j=st[i];j<=ed[i];j++){
dp[i][bnum+1].upd(j);
}
}
for(int j=bnum;j>i;j--){
dp[i][j]=dp[i][j+1];
for(int k=st[j];k<=ed[j];k++){
dp[i][j].upd(k);
}
}
}
int ans1=0,ans2=0;
while(q--){
int l,r;
cin>>l>>r;
l=(l+ans1-1)%n+1;
r=(r+ans1-1)%n+1;
if(l>r){
swap(l,r);
}
DP ans=dp[bel[l]-1][bel[r]+1];
for(int i=st[bel[l]];i<l;i++){
ans.upd(i);
}
for(int i=ed[bel[r]];i>r;i--){
ans.upd(i);
}
ans1=ans2=0;
for(int i=1;i<=m;i++){
ans1+=ans[i];
ans2^=ans[i];
}
ans1%=mod;
cout<<ans1<<" "<<ans2<<"\n";
}
}
namespace cplx{
bool end;
il double usdmem(){return (&begin-&end)/1048576.0;}
}
signed main(){
// cout<<cplx::usdmem();
ios::sync_with_stdio(0),cin.tie(0);
cin>>T;
while(T--){
solve();
}
return 0;
}
}
signed main(){return asbt::main();}
I. [SNOI2017]一个简单的询问
\(
\quad\sum{\operatorname{get}(l_1,r_1,x)\times\operatorname{get}(l_2,r_2,x)}\\
=\sum\operatorname{get}(1,l_1-1,x)\times\operatorname{get}(1,l_2-1,x)+\operatorname{get}(1,r_1,x)\times\operatorname{get}(1,r_2,x)-\operatorname{get}(1,l_1-1,x)\times\operatorname{get}(1,r_2,x)-\operatorname{get}(1,l_2-1,x)\times\operatorname{get}(1,r_1,x)
\)
将一个询问拆成 \(4\) 个,莫队给 \(l\) 指针和 \(r\) 指针各开一个桶即可。
Code
复制代码
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
using namespace std;
namespace asbt{
namespace cplx{bool begin;}
const int maxn=5e4+5;
int n,m,a[maxn],ans[maxn];
int blen,bel[maxn],tot;
int bucl[maxn],bucr[maxn];
struct wnti{
int l,r,id;
wnti(int l=0,int r=0,int id=0):l(l),r(r),id(id){}
il bool operator<(const wnti &x)const{
if(bel[l]==bel[x.l]){
return bel[l]&1?r>x.r:r<x.r;
}
return l<x.l;
}
}wt[maxn<<2];
namespace cplx{
bool end;
il double usdmem(){return (&begin-&end)/1048576.0;}
}
signed main(){
ios::sync_with_stdio(0),cin.tie(0);
cin>>n;
for(int i=1;i<=n;i++){
cin>>a[i];
}
cin>>m;
for(int i=1,l1,r1,l2,r2;i<=m;i++){
cin>>l1>>r1>>l2>>r2;
wt[++tot]=wnti(l1-1,l2-1,i);
wt[++tot]=wnti(r1,r2,i);
wt[++tot]=wnti(l1-1,r2,-i);
wt[++tot]=wnti(l2-1,r1,-i);
}
blen=n/sqrt(tot)+1;
for(int i=0;i<=n;i++){
bel[i]=i/blen;
}
sort(wt+1,wt+tot+1);
int l=0,r=0,res=0;
for(int i=1;i<=tot;i++){
while(l<wt[i].l){
bucl[a[++l]]++;
res+=bucr[a[l]];
}
while(r<wt[i].r){
bucr[a[++r]]++;
res+=bucl[a[r]];
}
while(l>wt[i].l){
res-=bucr[a[l]];
bucl[a[l--]]--;
}
while(r>wt[i].r){
res-=bucl[a[r]];
bucr[a[r--]]--;
}
if(wt[i].id>0){
ans[wt[i].id]+=res;
}
else{
ans[-wt[i].id]-=res;
}
}
for(int i=1;i<=m;i++){
cout<<ans[i]<<"\n";
}
return 0;
}
}
signed main(){return asbt::main();}
J. XOR and Favorite Number
考虑如何计算区间 \([l,r]\) 的异或和,显然做一个前缀异或和 \(pre\),答案即为 \(pre_r\oplus pre_{l-1}\)。那么在进行莫队时,设新增了一个 \(pre\) 值为 \(x\) 的点,那么对答案的贡献即为当前统计的 \(x\oplus k\) 的数量。时间复杂度 \(O(n\sqrt{m})\)。
Code
复制代码
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
using namespace std;
namespace asbt{
namespace cplx{bool begin;}
const int maxn=(1<<20)+5;
int n,m,k,blen;
int a[maxn],buc[maxn];
int ans[maxn],bel[maxn];
struct wnti{
int l,r,id;
il bool operator<(const wnti &x)const{
if(bel[l]==bel[x.l]){
return bel[l]&1?r>x.r:r<x.r;
}
return l<x.l;
}
}wt[maxn];
il void add(int x,int &res){
res+=buc[x^k];
buc[x]++;
}
il void del(int x,int &res){
buc[x]--;
res-=buc[x^k];
}
namespace cplx{
bool end;
il double usdmem(){return (&begin-&end)/1048576.0;}
}
signed main(){
ios::sync_with_stdio(0),cin.tie(0);
cin>>n>>m>>k;
for(int i=1;i<=n;i++){
cin>>a[i];
a[i]^=a[i-1];
}
for(int i=1;i<=m;i++){
cin>>wt[i].l>>wt[i].r;
wt[i].id=i;
}
blen=max(n/sqrt(m),1.0);
for(int i=1;i<=n;i++){
bel[i]=i/blen;
}
sort(wt+1,wt+m+1);
int l=1,r=0,res=0;
buc[0]=1;
for(int i=1;i<=m;i++){
// cout<<wt[i].l<<" "<<wt[i].r<<" "<<wt[i].id<<"\n";
while(l>wt[i].l){
add(a[--l-1],res);
}
while(r<wt[i].r){
add(a[++r],res);
}
// cout<<res<<"\n";
while(l<wt[i].l){
del(a[l++-1],res);
}
while(r>wt[i].r){
del(a[r--],res);
}
ans[wt[i].id]=res;
}
for(int i=1;i<=m;i++){
cout<<ans[i]<<"\n";
}
return 0;
}
}
signed main(){return asbt::main();}
/*
50 2 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
17 35
3 35
*/
K. String Set Queries
考虑所有集合内的字符串的不同长度不会超过 \(\sqrt{\sum|s_i|}\),因此直接枚举所有长度,哈希即可。时间复杂度 \(O(n\sqrt{n}\log{n})\)。
Code
复制代码
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
- 87
using namespace std;
namespace asbt{
namespace cplx{bool begin;}
const int maxn=3e5+5;
const ull bas1=13331;
const ll bas2=13327,mod2=1e9+7;
int n;
ull ha1[maxn],pw1[maxn];
ll ha2[maxn],pw2[maxn];
char s[maxn];
map<int,int> clen;
map<pair<ull,ll>,int> cha;
il ull gha1(int l,int r){
return ha1[r]-ha1[l-1]*pw1[r-l+1];
}
il ll gha2(int l,int r){
return (ha2[r]-ha2[l-1]*pw2[r-l+1]%mod2+mod2)%mod2;
}
namespace cplx{
bool end;
il double usdmem(){return (&begin-&end)/1048576.0;}
}
int main(){
pw1[0]=pw2[0]=1;
for(int i=1;i<=3e5;i++){
pw1[i]=pw1[i-1]*bas1;
pw2[i]=pw2[i-1]*bas2%mod2;
}
scanf("%d",&n);
while(n--){
int opt,len;
scanf("%d %s",&opt,s+1);
len=strlen(s+1);
switch(opt){
case 1:{
ull ha1=0;
ll ha2=0;
for(int i=1;i<=len;i++){
ha1=ha1*bas1+s[i];
ha2=(ha2*bas2+s[i])%mod2;
}
clen[len]++;
cha[mp(ha1,ha2)]++;
break;
}
case 2:{
ull ha1=0;
ll ha2=0;
for(int i=1;i<=len;i++){
ha1=ha1*bas1+s[i];
ha2=(ha2*bas2+s[i])%mod2;
}
if(--clen[len]==0){
clen.erase(len);
}
if(--cha[mp(ha1,ha2)]==0){
cha.erase(mp(ha1,ha2));
}
break;
}
default:{
int res=0;
for(int i=1;i<=len;i++){
ha1[i]=ha1[i-1]*bas1+s[i];
ha2[i]=(ha2[i-1]*bas2+s[i])%mod2;
}
for(pii i:clen){
for(int l=1,r=i.first;r<=len;l++,r++){
res+=cha[mp(gha1(l,r),gha2(l,r))];
}
}
printf("%d\n",res);
fflush(stdout);
break;
}
}
}
return 0;
}
}
int main(){return asbt::main();}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步