SMSC 2021 Day13&Day14 部分题解

Day13

  • 传播 spread (模拟)

真正的完美 inpref (数论,数论函数,线性筛)

P7788 [COCI2016-2017#6] Savrsen

考虑将 f f f 变为我们熟悉的函数,可以想到 ∣ i − f ( i ) ∣ = ∣ σ 1 ( i ) − 2 i ∣ |i-f(i)| = |\sigma_1(i)-2i| if(i)=σ1(i)2i ,其中 σ 1 ( n ) = ∑ d ∣ n d \sigma_1(n) = \sum_{d|n}d σ1(n)=dnd,是我们熟悉的约数和函数。它是一个积性函数,满足 a ⊥ b ⇔ f ( a ⋅ b ) = f ( a ) ⋅ f ( b ) a\bot b\Leftrightarrow f(a\cdot b) = f(a)\cdot f(b) abf(ab)=f(a)f(b)。所以考虑将 σ 1 \sigma_1 σ1 的计算加载到线性筛上。
在进行线性筛的过程中,除了筛选素数,在筛除合数的时候我们要计算它们的约数和。
下列式子显然:
σ 1 ( p ) = 1 + p , p  is a prime σ 1 ( K ⋅ p ) = σ 1 ( K ) × σ 1 ( p ) , p ⊥ K \begin{aligned} &\sigma_1(p) = 1 +p&,p\text{ is a prime}\\ &\sigma_1(K\cdot p) = \sigma_1(K)\times \sigma_1(p)&,p \bot K \end{aligned} σ1(p)=1+pσ1(Kp)=σ1(K)×σ1(p),p is a prime,pK
p  is a prime , K   m o d   p = 0 p\text{ is a prime} ,K \bmod p =0 p is a prime,Kmodp=0 时,我们考虑将 K ⋅ p K\cdot p Kp 构造成两个互质的数的乘积,由于在线性筛中,枚举到的质数 p p p K ⋅ p K\cdot p Kp 的最小质因子,所以我们考虑
K = ∏ p i e i × p k K ⋅ p = K p k × p k + 1 σ 1 ( K ⋅ p ) = σ 1 ( K ) σ 1 ( p k ) × σ 1 ( p k + 1 ) σ 1 ( p k + 1 ) = ∑ j = 0 k p j + p k + 1 σ 1 ( K ⋅ p ) = σ 1 ( K ) σ 1 ( p k ) × ( σ 1 ( p k ) × p + 1 ) K = \prod p_i^{ei}\times p^k \\[2ex] K\cdot p=\dfrac{K}{p^k}\times p^{k+1}\\[2ex] \sigma_1(K\cdot p) = \dfrac{\sigma_1(K)}{\sigma_1(p^k)}\times \sigma_1(p^{k+1}) \\[2ex] \sigma_1(p^{k+1}) = \sum_{j = 0}^{k} p^j + p^{k+1} \\[2ex] \sigma_1(K\cdot p) = \dfrac{\sigma_1(K)}{\sigma_1(p^k)}\times(\sigma_1(p^k)\times p + 1) K=piei×pkKp=pkK×pk+1σ1(Kp)=σ1(pk)σ1(K)×σ1(pk+1)σ1(pk+1)=j=0kpj+pk+1σ1(Kp)=σ1(pk)σ1(K)×(σ1(pk)×p+1)
由此得解。

#include<iostream>
#include<cstdio>

using namespace std;
typedef long long ll;
int n,sgm[10000005],cnt,p[10000005],pm[100000005],tmp;
bool NotPrime[10000005];
ll ans;

int myabs(int x)
{
	return x > 0 ? x : (-x);
}

int qpow(int x,int y)
{
	int res = 1;
	for(;y;y >>= 1)
	{
		if(y%2) res = res*x;
		x = x*x;
	}
	return res;
}

int main()
{
	scanf("%d",&n);
	NotPrime[1] = 1;sgm[1] = 1;
	for(int i = 2;i <= n;i ++)
	{
		if(NotPrime[i] == 0)
		{
			cnt ++;
			p[cnt] = i;
			sgm[i] = i + 1;
			pm[i] = 1;
		}
		for(int j = 1;j <= cnt && i*p[j] <= n;j ++)
		{
			NotPrime[i*p[j]] = 1;
			if(i%p[j] == 0)
			{
				tmp = qpow(p[j],pm[i]);
				sgm[i*p[j]] = sgm[i / tmp] * (sgm[tmp]*p[j] + 1);
				pm[i*p[j]] = pm[i] + 1;
				break;
			}
			sgm[i*p[j]] = sgm[i] * sgm[p[j]];
			pm[i*p[j]] = 1;
		}
	}
	for(int i = 1; i <= n;i ++)
	{
		ans += myabs(sgm[i] - i - i);
//		cout << sgm[i] << endl;
	}
	printf("%lld",ans);
	return 0;
}

两次 double (树状数组,可持久化线段树,莫队)

在这里插入图片描述
可以考虑树状数组离线回答询问。有一种巧妙的差分数组构造。考虑以下情况:
在这里插入图片描述
从当前的指针开始,第一个数字 i i i 不打标记,第二个数字 i i i 在树状数组对应位置中 + 1 +1 +1 ,第三个数字 i i i 在树状数组对应的位置中 − 1 -1 1 ,这样当且仅当查询的区间内包含恰好两个 i i i 时,会对答案贡献 1 1 1 表示这个区间内恰有两个数字 i i i
将询问按左端点降序排列后,从序列最右往左更新每个数的标记,更新到询问左端点时就回答询问,然后指针再向左移动,继续更新标记与回答询问,时间复杂度 O ( n ) O(n) O(n)。注意要离散化一下。

#include<iostream>
#include<cstdio>
#include<map>
#include<algorithm>

using namespace std;
typedef long long ll;
int n,q;
int pre1[500005],pre2[500005],bit[500005],pre3[500005];
ll a[500005],num[500005];

struct quest{
	int l;
	int r;
	int id;
	int ans;
}b[1000005];

bool cmp2(quest a,quest b)
{
	return a.id < b.id;
}

bool cmp1(quest a,quest b)
{
	if(a.l != b.l) return a.l > b.l;
	return a.r < b.r;
}

int lowbit(int x)
{
	return x&(-x);
}

int BIT_Sum(int i)
{
	int res = 0;
	for(;i;i -= lowbit(i)) res += bit[i];
	return res;
}

void BIT_Add(int i,int x)
{
	for(;i <= n;i += lowbit(i)) bit[i] += x;
	return ;
}

int main()
{
	map<ll ,ll > m;
	scanf("%d%d",&n,&q);
	for(int i = 1;i <= n;i ++) {
		scanf("%lld",&a[i]);
		num[i] = a[i];
	}
	sort(num + 1,num + 1 + n);
	for(int i = 1;i <= n;i ++) m[num[i]] = i;
	for(int i = 1;i <= n;i ++) a[i] = m[a[i]];
	for(int i = 1;i <= q;i ++)
	{
		scanf("%d%d",&b[i].l,&b[i].r);
		b[i].id = i;
	}
	sort(b + 1,b + 1 + q,cmp1);
	for(int i = 1,j = n;i <= q;i ++)
	{
		for(;j >= b[i].l;j --)
		{
			if(pre2[a[j]] == 0)
			{
				if(pre1[a[j]] == 0) pre1[a[j]] = j;
				else
				{
					pre2[a[j]] = pre1[a[j]];
					pre1[a[j]] = j;
					BIT_Add(pre2[a[j]],1);
				}
			}
			else
			{
				if(pre3[a[j]] > 0) BIT_Add(pre3[a[j]],1);
				BIT_Add(pre2[a[j]],-2);
				pre3[a[j]] = pre2[a[j]];
				pre2[a[j]] = pre1[a[j]];
				pre1[a[j]] = j;
				BIT_Add(pre2[a[j]],1);
			}
		}
		b[i].ans = BIT_Sum(b[i].r) - BIT_Sum(b[i].l - 1);
	}
	sort(b + 1,b + 1 + q,cmp2);
	for(int i = 1;i <= q;i ++) printf("%d\n",b[i].ans);
	return 0;
}
  • 重新开始 rbegin (状压DP,Trie)

Day14

  • 三角形 tri ()
  • 缩写 gal ()
  • 编辑距离 dis ()
  • 红与黑 red ()
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值