集训Day 2 2020.3.1 数论(质数与筛法)

集训Day 2 2020.3.1 还是数论复习

上节课作业

1.酒桶移动

三分!
【此处期待题解】
复杂度(O(nlog n))

2.POJ2142:The Balanc

有一天平和两种数量无限的砝码(重为(a)(b)),天平左右都可以放砝码,称质量为(c) 的物品,要求:
放置的砝码数量尽量少;
当砝码数量相同时,总质量尽量小。

题解

本质不就是(ax+by=c)吗,然后求(|x|+|y|)最小 且(|ax|+|by|)最小的可行解。
不难想到可能满足第一条的只有(x)正整数最小解和y正整数最小解这两种解,其中一个 就是答案

3.POJ2115:C Looooops

for(i=A;i!=B;i+=C){i%=1<< k;}
问:会循环多少次(有可能死循环)

题解

和跳青蛙差不多设(a=C),(b=2^k),(c=B-A)(ax+by=c)

素数和筛法

链接区:
数论
https://www.cnblogs.com/liuziwen0224/p/shulun1.html
Day1集训
https://www.cnblogs.com/liuziwen0224/p/xjx1.html

判定素数

int main(){
	int n;
	scanf("%d",&n);
	for(int i=2;i<=n;i++){
		int ok=0;
		for(int j=2;j<sqrt(i);j++){
			if(i%j==0) ok=1;
		}
	}
	return 0;
}

埃氏筛

复杂度(O(nloglog n))
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
1 2 3 / 5 / 7 / 9 / 11 / 13 / 15 / 17 / 19 /
1 2 3 / 5 / 7 / / / 11 / 13 / / / 17 / 19 /(3)
1 2 3 / 5 / 7 / / / 11 / 13 / / / 17 / 19 /(5)
1 2 3 / 5 / 7 / / / 11 / 13 / / / 17 / 19 /(7)...

bool he[10000005]={0};
void Eratosthenes(int n){
	for(int i=2;i<=n;i++){
		if(he[i]) continue;
		for(int j=2;j*i<=n;j++) he[j*i]=1;
	}
}

例题讲解

1.POJ2689:Prime Distance

给不超过int的(l,r),其中(r-l+1 le 10^6),筛出其中的素数,并且求出相邻素数差值最大和最小的一对。

题解

  1. 提示:区间内的合数的质因子一定有在50000以内的

证明:如果不存在一个小于50000的,由于一个数至少有两个质因数,则大于50000的前两个质数(m,n)的乘积(mn>50000^2> ext {int})

  1. 筛出50000以内的素数,用它们来筛出[l,r]内的合数.
    怎么筛是个问题,假设我们有一素数(p)(并且筛完了素数(p)以前所有素数的倍数),我们显然希望找到第一个在区间内的素数的倍数,然后用筛法筛区间内的合数即可。

  2. 显然(p^2)是一个没被筛过的合数,如果(p^2<L),那么我们第一个筛的合数就应该是((l+p- 1)/p*p)(C++意义).
    如果(lle p^2 le r),那么第一个筛的合数就是(p^2),如果(p^2>r)那就不用筛了。
    然后对第一个筛的合数不断+p直到超过(r), 然后这些合数全筛走,剩下的就是质数.

  3. 其余细节也有很多,很有必要一写。

2.POJ3421:X-factor Chains

构造一个数列,起始为(1),终止为一给定数(X),满足(X_i < X_{i+1}) 并且(X_i | X_{i+1})。求出数列 最大长度和该长度下的情况数。((X<2^{20}))

题解

(X)分解质因数(假设有(n)个),要想最长显然它前面那个数是(n-1)个质因数相乘,那么再前面的那个数是(n-1)(n-2)个质因数相乘……以此类推,长度就是(n+1)(题要求输出此数(-1)
即:
(F)的质因数为(f_i)(n)个,构造(1,f_1,f_1f_2,f_1f_2f_3,...,X=prodlimits_{i=1}^nf_i)
方案数就是有重元素的排列了

3.CF449C:Jzzhu and Apples

https://www.luogu.com.cn/problem/CF449C

有数(1)~(n),要求配对,每对最大公约数不能为(1),求最大配对数。((nle 10^5)

题解

  1. 贪心,显然有大素数因子的数难配对,于是从大到小枚举素数(p),那么(p,2p,3p)…… 都可以两两配对(前提是这个数没被配过)
  2. 那么如果一共是偶数个的话我们显然可以全配了。
  3. 如果是奇数个肯定要扔掉一个数。把(2p)扔掉,然后这些扔掉的数到了(p=2)的 时候就会自己互相配对啦。
  4. 不难发现我们最大化利用了每个数。

(第一遍的时候的错误思路)
筛到素数(p)(p)之后的所有倍数的个数(n),为偶数时情况数(ans=dfrac{n}{2}),奇数时把最后一个数留下,也许还有可能和别的配对,(p)从小到大遍历

下期预告:中国剩余定理

【此处留白】

课后练习

1.LGP2758 编辑距离

设A和B是两个字符串。我们要用最少的字符操作次数,将字符串A转换为字符串B。
这里所说的字符操作共有三种:
1、删除一个字符;
2、插入一个字符;
3、将一个字符改为另一个字符;
皆为小写字母

题解

由于对于字符串的操作只有4种情况(删除,添加、更改、不变),所以该题的子问题就是进行了这4种操作后的A字符串变为B字符串需要多少步。记录(dp_{i,j})的意义为把第一个字符串的1$i$位变为第二个字符串的1(j)位需要多少步

转移方程
  1. 删:(dp_{i-1,j}+1)
    字符串A的前i-1个字符变为字符串B的前j个需要多少步[把字符串的第i个字符(最后一个)删除了],删除需要一步因此加1
  2. 添:(dp_{i,j-1}+1)
    (B_j)字符加在A字符串的最后面即添加,同样可以理解为将(B_j)字符删掉,因为不用再考虑了。字符串A的前(i)个字符变为字符串B的前(j-1)个需要多少步 添加需要一步因此加(1)
  3. 替:(dp_{i-1,j-1}+1)
    字符串A和B的最后两个都相等了,因此都不用再考虑。字符串A的前(i-1)个字符变为字符串B的前(j-1)个需要多少步 添加需要一步因此加(1)
  4. 不变:(dp_{i-1,j-1})
    字符串A和B的最后两个都相等,不考虑。
#include <cstdio>
#include <algorithm>
#include <cmath>
using namespace std;
char s1[2005],s2[2005];
int edit[2005][2005];
int dp(int i,int j){ 
    if(edit[i][j]!=-1) return edit[i][j]; 
    if(i==0) return edit[i][j]=j;
    if(j==0) return edit[i][j]=i;
    int bonus=1;
    if(s1[i]==s2[j]) bonus=0;  
    return edit[i][j]=min(min(dp(i-1,j)+1,dp(i,j-1)+1),dp(i-1,j-1)+bonus);
}
int main(){
    scanf("%s
%s",s1+1,s2+1);
    memset(edit,-1,sizeof(edit));
    int len1=strlen(s1+1),len2=strlen(s2+1);
    dp(len1,len2);
    printf("%d",edit[len1][len2]);
    return 0;
}

贴上大神吴昊恒博客及代码:
https://www.luogu.com.cn/blog/arookieoier/post-20200301-ji-xun-lian-xi-ti

2.JSK43511

https://nanti.jisuanke.com/t/43511

给两个由az和09组成的字符串,你可以 对任意一个字符串做如下操作:

  1. 在一个地方插入一个字母
  2. 删除一个字母
  3. 删除一个数字(k),然后在此处插入(k)个字母
    问最少几步使得两个字符串相同且没有数字存在?
    第一个字符串长10000,第二个长1000, 数字最多100个

题解

【待补充】

要做就做南波万
原文地址:https://www.cnblogs.com/liuziwen0224/p/xjx2.html