挑了两题放上来
1
ST表区间 gcd ,然后要某个区间可以有留着的话,只可能是那个 gcd 且是区间最小值,所以再弄个东西统计一下区间最小以及其个数就行了。
#include <bits/stdc++.h>
using namespace std;
#define MAXN (100005)
int a[MAXN][30];
int b[MAXN][30];
int c[MAXN][30];
int n,Q;
int gcd(int a, int b)
{
return b ? gcd(b,a%b) : a;
}
int QRY_gcd(int L, int R)
{
int len=R-L;
int ret=a[L][0];
L++;
for (int i=0; len; i++,len>>=1) {
if (len&1) {
ret=gcd(ret,a[L][i]);
L+=(1<<i);
}
}
return ret;
}
int QRY_min(int L, int R)
{
int len=R-L;
int ret=b[L][0];
L++;
for (int i=0; len; i++,len>>=1) {
if (len&1) {
ret=min(ret,b[L][i]);
L+=(1<<i);
}
}
return ret;
}
int QRY_cnt(int L, int R, int v)
{
int len=R-L;
int ret=(a[L][0]==v);
L++;
for (int i=0; len; i++,len>>=1) {
if (len&1) {
if (b[L][i]==v)
ret+=c[L][i];
L+=(1<<i);
}
}
return ret;
}
void solve()
{
scanf("%d",&n);
for (int i=1; i<=n; i++) {
scanf("%d",&a[i][0]);
b[i][0]=a[i][0];
c[i][0]=1;
}
for (int j=1; j<=25; j++) {
for (int i=1; (i+(1<<(j-1)))<=n; i++) {
a[i][j]=gcd(a[i][j-1],a[i+(1<<(j-1))][j-1]);
b[i][j]=min(b[i][j-1],b[i+(1<<(j-1))][j-1]);
if (b[i][j-1] == b[i+(1<<(j-1))][j-1])
c[i][j]=c[i][j-1]+c[i+(1<<(j-1))][j-1];
else if (b[i][j-1] < b[i+(1<<(j-1))][j-1])
c[i][j]=c[i][j-1];
else
c[i][j]=c[i+(1<<(j-1))][j-1];
}
}
scanf("%d",&Q);
for (int ttt=1,ll,rr,g,m,tmp; ttt<=Q; ttt++) {
scanf("%d%d",&ll,&rr);
g=QRY_gcd(ll,rr);
m=QRY_min(ll,rr);
if (g==m) {
tmp=QRY_cnt(ll,rr,m);
printf("%d\n",rr-ll+1-tmp);
}
else {
printf("%d\n",rr-ll+1);
}
}
}
int main()
{
solve();
return 0;
}
2
挺巧妙的。没有重复数字是关键。
是 cf 上这题的弱小版。
https://codeforces.com/contest/1553/problem/F
#include <bits/stdc++.h>
#define MAXVAL 300005
#define lowbit(x) ((x)&(-(x)))
int n;
long long a;
long long c[MAXVAL+10];
void ADD(int X, int V)
{
for (; X<=MAXVAL; X+=lowbit(X))
c[X]+=V;
}
long long QRY(int X)
{
long long ret=0,x;
for (x=X; x>0; x-=lowbit(x)) ret+=c[x];
return ret;
}
int main()
{
scanf("%d",&n);
for (int i=1,j; i<=n; i++) {
scanf("%lld",&a);
printf("%lld\n",(i-1)*a-QRY(a));
for (j=a; j<=MAXVAL; j+=a) {
ADD(j,a);
}
}
return 0;
}
/*
5
185 45 135 121 84
*/