自己开的练习赛:(三个模板题)
https://vjudge.net/contest/239597#problem
莫队算法:给定一个区间(l,r)的结果,求问(l+1,r),(l,r+1),(l-1,r)(l,r-1);
核心:
一个修改函数;(先减去之前的,挪到现在的位置,加上现在的)
四个while;
(先更新,再挪L);
模板:
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cmath>
#include<cstring>
using namespace std;
typedef long long int ll;
const int N=3e5+5;
const int MAX=1e6+5;
int unit,arr[N];
ll ans=0,pes[N],res[N],cnt[MAX];
struct node
{
int l,r,id;
} q[N];
bool cmp(node a,node b)
{
return a.l/unit!=b.l/unit?a.l/unit<b.l/unit:a.r<b.r;
}
void add(int pos) //减去原来的位置,加上现在的位置
{
ans=ans-cnt[arr[pos]]*cnt[arr[pos]];
cnt[arr[pos]]++;
ans=ans+cnt[arr[pos]]*cnt[arr[pos]];
}
void remove(int pos)//减去原来的位置,加上现在的位置
{
ans=ans-cnt[arr[pos]]*cnt[arr[pos]];
cnt[arr[pos]]--;
ans=ans+cnt[arr[pos]]*cnt[arr[pos]];
}
int main()
{
int n,m;
scanf("%d",&n);
scanf("%d",&m);
unit=sqrt(n);
for(int i=1; i<=n; i++)
{
scanf("%d",&arr[i]);
}
for(int i=1; i<=m; i++)
{
scanf("%d%d",&q[i].l,&q[i].r);
q[i].id=i;
}
sort(q+1,q+m+1,cmp);
int L=q[1].l,R=L-1;
for(int i=1; i<=m; i++)
{
while(L>q[i].l)
add(--L);
while(L<q[i].l)
remove(L++);
while(R>q[i].r)
remove(R--);
while(R<q[i].r)
add(++R);
res[q[i].id]=ans-(R-L+1);
pes[q[i].id]=(ll)(R-L+1)*(R-L);
}
for(int i=1; i<=m; i++)
{
ll p=__gcd(res[i],pes[i]);
printf("%lld/%lld\n",res[i]/p,pes[i]/p);
}
}
第一个题:
题意:一个区间内不同的数有多少个;
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cmath>
using namespace std;
const int N=3e5+5;//区间范围
const int MAX=1e6+5;//最大数字
int unit,cnt[MAX],arr[N],res[N],ans=0;
struct node
{
int l,r,id;
} q[N];
bool cmp(node a,node b)
{
return a.l/unit!=b.l/unit?a.l/unit<b.l/unit:a.r<b.r;
}
void add(int pos)
{
cnt[arr[pos]]++;
if(cnt[arr[pos]]==1)
{
ans++;
}
}
void remove(int pos)
{
cnt[arr[pos]]--;
if(cnt[arr[pos]]==0)
{
ans--;
}
}
int main()
{
int n;
scanf("%d",&n);
unit=sqrt(n);
for(int i=1; i<=n; i++)
{
scanf("%d",&arr[i]);
}
int m;
scanf("%d",&m);
for(int i=1; i<=m; i++)
{
scanf("%d%d",&q[i].l,&q[i].r);
q[i].id=i;
}
sort(q+1,q+m+1,cmp);
int L=q[1].l,R=L-1;
for(int i=1; i<=m; i++)
{
while(L>q[i].l)
add(--L);
while(L<q[i].l)
remove(L++);
while(R>q[i].r)
remove(R--);
while(R<q[i].r)
add(++R);
res[q[i].id]=ans;
}
for(int i=1; i<=m; i++)
{
printf("%d\n",res[i]);
}
}
第二个题:
小z的袜子;
求概率:
本题公式:((a^2+b^2+……)-(R-L+1))/((R-L+1)*(R-L))
代码:
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cmath>
#include<cstring>
using namespace std;
typedef long long int ll;
const int N=3e5+5;
const int MAX=1e6+5;
int unit,arr[N];
ll ans=0,pes[N],res[N],cnt[MAX];
struct node
{
int l,r,id;
} q[N];
bool cmp(node a,node b)
{
return a.l/unit!=b.l/unit?a.l/unit<b.l/unit:a.r<b.r;
}
void add(int pos) //减去原来的位置,加上现在的位置
{
ans=ans-cnt[arr[pos]]*cnt[arr[pos]];
cnt[arr[pos]]++;
ans=ans+cnt[arr[pos]]*cnt[arr[pos]];
}
void remove(int pos)//减去原来的位置,加上现在的位置
{
ans=ans-cnt[arr[pos]]*cnt[arr[pos]];
cnt[arr[pos]]--;
ans=ans+cnt[arr[pos]]*cnt[arr[pos]];
}
int main()
{
int n,m;
scanf("%d",&n);
scanf("%d",&m);
unit=sqrt(n);
for(int i=1; i<=n; i++)
{
scanf("%d",&arr[i]);
}
for(int i=1; i<=m; i++)
{
scanf("%d%d",&q[i].l,&q[i].r);
q[i].id=i;
}
sort(q+1,q+m+1,cmp);
int L=q[1].l,R=L-1;
for(int i=1; i<=m; i++)
{
while(L>q[i].l)
add(--L);
while(L<q[i].l)
remove(L++);
while(R>q[i].r)
remove(R--);
while(R<q[i].r)
add(++R);
res[q[i].id]=ans-(R-L+1);
pes[q[i].id]=(ll)(R-L+1)*(R-L);
}
for(int i=1; i<=m; i++)
{
ll p=__gcd(res[i],pes[i]);
printf("%lld/%lld\n",res[i]/p,pes[i]/p);
}
}
第三个题:
题意:(p[y]*p[y]*y的和)p[y]:数值为y的数出现的个数;
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cmath>
#include<cstring>
using namespace std;
typedef long long int ll;
const int maxn=200005;
const int maxa=1e6;
int n,m;
struct node
{
int l,r,id;
} q[maxn];
int cmp(const node& a,const node& b){
if(a.l/(int)sqrt(m)!=b.l/(int)sqrt(m)) return a.l/(int)sqrt(m)<b.l/(int)sqrt(m);
return a.r<b.r;
}
int arr[maxn];
int cnt[maxa+5];
ll ans,res[maxn];
void update(int cur,int change)
{
ans-=(ll)cnt[arr[cur]]*cnt[arr[cur]]*arr[cur];
cnt[arr[cur]]+=change;
ans+=(ll)cnt[arr[cur]]*cnt[arr[cur]]*arr[cur];
}
void solve()
{
ans=arr[1];
cnt[arr[1]]++;
int L=1;
int R=1;
for(int i=1; i<=m; i++)
{
while(L<q[i].l)
{
update(L,-1);
L++;
}
while(L>q[i].l)
{
L--;
update(L,1);
}
while(R>q[i].r)
{
update(R,-1);
R--;
}
while(R<q[i].r)
{
R++;
update(R,1);
}
res[q[i].id]=ans;
}
}
int main()
{
while(~scanf("%d%d",&n,&m))
{
for(int i=1; i<=n; i++)
{
scanf("%d",&arr[i]);
}
for(int i=1; i<=m; i++)
{
scanf("%d%d",&q[i].l,&q[i].r);
q[i].id=i;
}
sort(q+1,q+m+1,cmp);
memset(cnt,0,sizeof(cnt));
solve();
for(int i=1; i<=m; i++)
{
cout<<res[i];
printf("\n");
}
}
}
快速读入,快速输出:
(由于putchar()比scanf,print快);
int read()
{
ll x=0;
char c=getchar();
while(c < '0' || c > '9')
{
c = getchar();
}
while(c >= '0' && c <= '9')
{
x = x * 10 + c - '0';
c = getchar();
}
return x;
}
void out(ll x)
{
if(x < 0)
{
putchar('-');
x = -x;
}
if (x >= 10)
{
out(x / 10);
}
putchar(x % 10 + '0');
}
//arr[i]=read();
//q[i].l=read();
// q[i].r=read();
//out(res[i]);
莫队的另一个题:牛客网暑假acm第一次多校训练:
(j签到题)(包含了莫队及输入输出)
#include <bits/stdc++.h>
using namespace std;
struct papp
{
int l;
int r;
int id;
} a[200005];
int read()
{
int x=0;
char c=getchar();
while(c < '0' || c > '9')
{
c = getchar();
}
while(c >= '0' && c <= '9')
{
x = x * 10 + c - '0';
c = getchar();
}
return x;
}
void out(int x)
{
if(x < 0)
{
putchar('-');
x = -x;
}
if (x >= 10)
{
out(x / 10);
}
putchar(x % 10 + '0');
}
int ma;
int cmp(papp a,papp b)
{
if(a.l/ma==b.l/ma)
{
return a.r<b.r;
}
else
{
return a.l/ma<b.l/ma;
}
}
int sum,num[200005],ans[200005];
void pan(int n)
{
num[n]++;
if(num[n]==1)
{
sum++;
}
}
void pan1(int n)
{
num[n]--;
if(num[n]==0)
{
sum--;
}
}
int str[200005];
int main()
{
int n,m;
while(~scanf("%d%d",&n,&m))
{
sum=0;
memset(ans,0,sizeof(ans));
memset(num,0,sizeof(num));
int l=0,r=0;
ma=sqrt(n);
for(int i=1; i<=n; i++)
{
str[i]=read();
str[n+i]=str[i];
}
int x1,x2;
for(int i=1; i<=m; i++)
{
x1=read();
x2=read();
a[i].l=x2;
a[i].r=x1+n;
a[i].id=i;
}
sort(a+1,a+m+1,cmp);
l=a[1].l,r=l-1;
for(int i=1; i<=m; i++)
{
while(r<a[i].r)
{
r++,pan(str[r]);
}
while(r>a[i].r)
{
pan1(str[r]),r--;
}
while(l<a[i].l)
{
pan1(str[l]),l++;
}
while(l>a[i].l)
{
l--,pan(str[l]);
}
ans[a[i].id]=sum;
}
for(int i=1; i<=m; i++)
{
out(ans[i]);
printf("\n");
}
}
return 0;
}