集训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),筛出其中的素数,并且求出相邻素数差值最大和最小的一对。
题解
- 提示:区间内的合数的质因子一定有在50000以内的
证明:如果不存在一个小于50000的,由于一个数至少有两个质因数,则大于50000的前两个质数(m,n)的乘积(mn>50000^2> ext {int})
-
筛出50000以内的素数,用它们来筛出[l,r]内的合数.
怎么筛是个问题,假设我们有一素数(p)(并且筛完了素数(p)以前所有素数的倍数),我们显然希望找到第一个在区间内的素数的倍数,然后用筛法筛区间内的合数即可。 -
显然(p^2)是一个没被筛过的合数,如果(p^2<L),那么我们第一个筛的合数就应该是((l+p- 1)/p*p)(C++意义).
如果(lle p^2 le r),那么第一个筛的合数就是(p^2),如果(p^2>r)那就不用筛了。
然后对第一个筛的合数不断+p直到超过(r), 然后这些合数全筛走,剩下的就是质数. -
其余细节也有很多,很有必要一写。
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))
题解
- 贪心,显然有大素数因子的数难配对,于是从大到小枚举素数(p),那么(p,2p,3p)…… 都可以两两配对(前提是这个数没被配过)
- 那么如果一共是偶数个的话我们显然可以全配了。
- 如果是奇数个肯定要扔掉一个数。把(2p)扔掉,然后这些扔掉的数到了(p=2)的 时候就会自己互相配对啦。
- 不难发现我们最大化利用了每个数。
(第一遍的时候的错误思路)
筛到素数(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)位需要多少步
转移方程
- 删:(dp_{i-1,j}+1)
字符串A的前i-1个字符变为字符串B的前j个需要多少步[把字符串的第i个字符(最后一个)删除了],删除需要一步因此加1 - 添:(dp_{i,j-1}+1)
将(B_j)字符加在A字符串的最后面即添加,同样可以理解为将(B_j)字符删掉,因为不用再考虑了。字符串A的前(i)个字符变为字符串B的前(j-1)个需要多少步 添加需要一步因此加(1) - 替:(dp_{i-1,j-1}+1)
字符串A和B的最后两个都相等了,因此都不用再考虑。字符串A的前(i-1)个字符变为字符串B的前(j-1)个需要多少步 添加需要一步因此加(1) - 不变:(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组成的字符串,你可以 对任意一个字符串做如下操作:
- 在一个地方插入一个字母
- 删除一个字母
- 删除一个数字(k),然后在此处插入(k)个字母
问最少几步使得两个字符串相同且没有数字存在?
第一个字符串长10000,第二个长1000, 数字最多100个
题解
【待补充】