1. 程式人生 > 其它 >大端 小端

大端 小端

oi-wiki

核心思路:離線演算法,把每次的詢問先記錄下來,按一定的順序排序,然後暴力從上一個區間轉移到下一個區間。

複雜度:

  1. \(n\) ,\(m\) 同階時,塊長取 \(\sqrt n\) 時,複雜度為 \(O(n \sqrt n)\)
  2. \(m < n\) 時,塊長取 \(\displaystyle \frac{n}{\sqrt{m}}\) 時,複雜度為 \(O(n \sqrt m)\) .

例題 小 Z 的襪子

分析可見 oi-wiki ( /xyx

code

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;

const int N=1e5+10;
int n,m,k,a[N],ans[N],s[N],ps[N],l,r,blo,sm;
ll L[N],R[N];
struct node{
	int l,r,sum;
	void in(int x){scanf("%d%d",&l,&r);sum=x;L[x]=l,R[x]=r;}
}qr[N];

bool cmp(node x,node y){return ps[x.r]==ps[y.r]?x.l<y.l:x.r<y.r;}

int gx(int x){return s[a[x]]*(s[a[x]]-1)/2;}

int main()
{
	scanf("%d%d",&n,&m);
	blo=n/sqrt(m*2/3);l=1;
	for(int i=1;i<=n;i++) scanf("%d",&a[i]),ps[i]=(i-1)/blo+1;
	for(int i=1;i<=m;i++) qr[i].in(i);
	sort(qr+1,qr+m+1,cmp);
	for(int i=1;i<=m;i++)
	{
		while(l<qr[i].l) sm-=gx(l),s[a[l]]--,sm+=gx(l),l++;
		while(l>qr[i].l) l--,sm-=gx(l),s[a[l]]++,sm+=gx(l);
		while(r<qr[i].r) r++,sm-=gx(r),s[a[r]]++,sm+=gx(r);
		while(r>qr[i].r) sm-=gx(r),s[a[r]]--,sm+=gx(r),r--;
		ans[qr[i].sum]=sm;
	}
	for(int i=1;i<=m;i++)
	{
		if(L[i]==R[i]) {puts("0/1");continue;}
		int gcd=__gcd(ans[i]*1ll,(R[i]-L[i]+1)*1ll*(R[i]-L[i])/2*1ll);
		printf("%d/%lld\n",ans[i]/gcd,(R[i]-L[i]+1)*1ll*(R[i]-L[i])/2*1ll/gcd);
	}
	return 0;
}

大數

如果直接求一個序列的答案,發現並不好求。於是考慮求以 \(l\) 為左端點(右端點類似)所造成的貢獻,顯然,當滿足 \(\displaystyle \frac{ s[r]−s[l−1]}{10^{n−r}}\equiv0\pmod{p}\),就找到了一個合法的區間(\(s[i]\) 表示由前 \(i\) 個數和後 \(n−i\)\(0\) 構成的數字)。這樣我們發現,假設我們已知一個區間的答案,可以做到 \(O(1)\) 移動一個單位的端點。而我們要求的,實際上就是區間中等於某個數的位置個數。可以將其離散化之後,用莫隊+桶維護。

code

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;

const int N=1e5+10;
inline int read()
{
    int x=0,w=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if (ch=='-')w=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
    return x*w;
}
#define int long long
inline int lread()
{
    int x=0,w=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if (ch=='-')w=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
    return x*w;
}
#undef int

int q,ps[N],n,cnt[N],tot,vi[N];
char s[N];ll res[N],ans[N],nw,v[N],t[N],p,x,fc=1;
struct node{
	int l,r,id;
	bool operator <(const node &y)const{
		return ps[l]==ps[y.l]?r<y.r:ps[l]<ps[y.l];
	}	
}qr[N];

void tepan()
{
	int l,r;
	for(int i=1;i<=n;i++)
	{
		res[i]=res[i-1],cnt[i]=cnt[i-1];
		if((s[i]-'0')%p==0) res[i]+=i,cnt[i]++;
	}
	while(q--)
		l=read(),r=read(),printf("%lld\n",res[r]-res[l-1]-(ll)(cnt[r]-cnt[l-1])*(l-1));
	exit(0);
}

void upd(int x)
{
	nw-=(ll)(cnt[v[x]]-1)*cnt[v[x]]/2;
	if(!vi[x]) cnt[v[x]]++;else cnt[v[x]]--;
	vi[x]^=1;nw+=(ll)(cnt[v[x]]-1)*cnt[v[x]]/2;
}

int main()
{
	p=lread();scanf("%s",s+1);q=read();
	n=strlen(s+1);int sz=sqrt(n)+1;
	if(p==2||p==5) tepan();
	for(int i=1;i<=n;i++) ps[i]=(i-1)/sz+1;
	for(int i=n;i;i--)
		x=(x+(ll)(s[i]-'0')*fc)%p,fc=(ll)fc*10%p,v[i]=t[i]=x;
	v[++n]=t[n]=0;
	
	sort(t+1,t+n+1);tot=unique(t+1,t+n+1)-t-1;
	for(int i=1;i<=n;i++) v[i]=lower_bound(t+1,t+tot+1,v[i])-t;
	
	for(int i=1;i<=q;i++) qr[i].l=read(),qr[i].r=read()+1,qr[i].id=i;
	sort(qr+1,qr+q+1);	
	int l=1,r=0;
	for(int i=1;i<=q;i++)
	{
		while(r<qr[i].r) upd(++r);
		while(l>qr[i].l) upd(--l);
		while(r>qr[i].r) upd(r--);
		while(l<qr[i].l) upd(l++);

		ans[qr[i].id]=nw;
	}
	
	for(int i=1;i<=q;i++) printf("%lld\n",ans[i]);
	
    return 0;
}

\(\texttt{End.}\)