CODEFORCES ROUND #641 (DIV. 2)【A-C】

http://www.yyycode.cn/index.php/2020/05/16/codeforces-round-641-div-2%e3%80%90a-c%e3%80%91/


如果图片看不到来我博客看叭

A. Orac and Factors

https://codeforces.com/contest/1350/problem/A

Orac is studying number theory, and he is interested in the properties of divisors.

For two positive integers aa and bb, aa is a divisor of bb if and only if there exists an integer cc, such that a⋅c=ba⋅c=b.

For n≥2n≥2, we will denote as f(n)f(n) the smallest positive divisor of nn, except 11.

For example, f(7)=7,f(10)=2,f(35)=5f(7)=7,f(10)=2,f(35)=5.

For the fixed integer nn, Orac decided to add f(n)f(n) to nn.

For example, if he had an integer n=5n=5, the new value of nn will be equal to 1010. And if he had an integer n=6n=6, nn will be changed to 88.

Orac loved it so much, so he decided to repeat this operation several times.

Now, for two positive integers nn and kk, Orac asked you to add f(n)f(n) to nn exactly kk times (note that nn will change after each operation, so f(n)f(n) may change too) and tell him the final value of nn.

For example, if Orac gives you n=5n=5 and k=2k=2, at first you should add f(5)=5f(5)=5 to n=5n=5, so your new value of nn will be equal to n=10n=10, after that, you should add f(10)=2f(10)=2 to 1010, so your new (and the final!) value of nn will be equal to 1212.

Orac may ask you these queries many times.Input

The first line of the input is a single integer t (1≤t≤100)t (1≤t≤100): the number of times that Orac will ask you.

Each of the next tt lines contains two positive integers n,k (2≤n≤106,1≤k≤109)n,k (2≤n≤106,1≤k≤109), corresponding to a query by Orac.

It is guaranteed that the total sum of nn is at most 106106.Output

Print tt lines, the ii-th of them should contain the final value of nn in the ii-th query by Orac.ExampleinputCopy

3
5 1
8 2
3 4

outputCopy

10
12
12

Note

In the first query, n=5n=5 and k=1k=1. The divisors of 55 are 11 and 55, the smallest one except 11 is 55. Therefore, the only operation adds f(5)=5f(5)=5 to 55, and the result is 1010.

In the second query, n=8n=8 and k=2k=2. The divisors of 88 are 1,2,4,81,2,4,8, where the smallest one except 11 is 22, then after one operation 88 turns into 8+(f(8)=2)=108+(f(8)=2)=10. The divisors of 1010 are 1,2,5,101,2,5,10, where the smallest one except 11 is 22, therefore the answer is 10+(f(10)=2)=1210+(f(10)=2)=12.

In the third query, nn is changed as follows: 3→6→8→10→123→6→8→10→12.


日常拉题面拉出问题

题意:对每个数,找出这个数的最小正因数,进行K次相加(每次加的过程中最小正因数针对当前数)

思路:暴力的话1e6O(n*klogn)必定超时,那我们预处理:1.先判断是否是偶数,偶数直接加 2.预处理出每个数的最小正因子O(logn),同时判断这个数是不是质数 3.如果这个数是质数则加质数的则加本身之后(k-1)*2;其他就是奇数加最小正因数然后(k-1)*2;

dbq这里说错了。求那个最小正因数是sqrt(n)的

反思:暴力超时可以往预处理的方向去思考

#include<iostream>
#include<vector>
#include<queue>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn=1e6+10;
typedef long long LL;
LL f[maxn]; 

bool fabs1(LL n)
{
	for(LL i=2;i<=n/i;i++)
	{
		if(n%i==0)
		{
			return false; break;
		}
	}
	return true;
}
LL fabs2(LL n)
{
	for(LL i=2;i<=n/i;i++)
	{
		if(n%i==0)
		{
			return i; break;
		}
	}
	return n;
}
int main(void)
{
	for(LL i=2;i<=1e6;i++)
		f[i]=fabs2(i);
	LL t;cin>>t;
	while(t--)
	{
		LL n,k;cin>>n>>k;
		//偶数 
		if(n%2==0) cout<<(n+2*k)<<endl;
		//质数 
		else if(fabs1(n)==true)
		{
			cout<<(n+n+(k-1)*2)<<endl;
		}
		else if(n%2==1)
		{
			n+=f[n];
			n=n+(k-1)*2;
			cout<<n<<endl;
		}
	}
return 0;
}

B. Orac and Models

https://codeforces.com/contest/1350/problem/B

There are nn models in the shop numbered from 11 to nn, with sizes s1,s2,…,sns1,s2,…,sn.

Orac will buy some of the models and will arrange them in the order of increasing numbers (i.e. indices, but not sizes).

Orac thinks that the obtained arrangement is beatiful, if for any two adjacent models with indices ijij and ij+1ij+1 (note that ij<ij+1ij<ij+1, because Orac arranged them properly), ij+1ij+1 is divisible by ijij and sij<sij+1sij<sij+1.

For example, for 66 models with sizes {3,6,7,7,7,7}{3,6,7,7,7,7}, he can buy models with indices 11, 22, and 66, and the obtained arrangement will be beautiful. Also, note that the arrangement with exactly one model is also considered beautiful.

Orac wants to know the maximum number of models that he can buy, and he may ask you these queries many times.Input

The first line contains one integer t (1≤t≤100)t (1≤t≤100): the number of queries.

Each query contains two lines. The first line contains one integer n (1≤n≤100000)n (1≤n≤100000): the number of models in the shop, and the second line contains nn integers s1,…,sn (1≤si≤109)s1,…,sn (1≤si≤109): the sizes of models.

It is guaranteed that the total sum of nn is at most 100000100000.Output

Print tt lines, the ii-th of them should contain the maximum number of models that Orac can buy for the ii-th query.ExampleinputCopy

4
4
5 3 4 6
7
1 4 2 3 6 4 9
5
5 4 3 2 1
1
9

outputCopy

2
3
1
1

Note

In the first query, for example, Orac can buy models with indices 22 and 44, the arrangement will be beautiful because 44 is divisible by 22 and 66 is more than 33. By enumerating, we can easily find that there are no beautiful arrangements with more than two models.

In the second query, Orac can buy models with indices 11, 33, and 66. By enumerating, we can easily find that there are no beautiful arrangements with more than three models.

In the third query, there are no beautiful arrangements with more than one model.


题意:有一段序列,求出满足下标是整除关系的并且下标是整除关系的对应值是后大于前这样的最大数量是多少

思路:类似“最长上升子序列的dp”和“欧拉筛”的循环++

利用j+=i来达到整除的筛子,常规的最长上升子序列是dp[i]表示在i位置的最长上升子序列数,这里用dp[j]来表示,dp[j]表示在j位置上的最长上升子序列数,同时记录出现的最大值

#include<iostream>
#include<vector>
#include<queue>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn=1e5+10;
typedef long long ll;
int t;
ll s[maxn];
int dp[maxn];
int n;
int main()
{
   cin>>t;
   while(t--)
   {
       scanf("%d",&n);
       for(int i=1;i<=n;i++)
       {
           scanf("%lld",&s[i]);
           dp[i]=1;
       }
       int maxx=1;
       for(int i=1;i<=n;i++)
       {
           for(int j=i;j<=n;j+=i)
            if(s[j]>s[i]) {dp[j]=max(dp[i]+1,dp[j]);maxx=max(maxx,dp[j]);}
       }
       cout<<maxx<<endl;
   }
   return 0;
}


C. Orac and LCM

https://codeforces.com/contest/1350/problem/C

For the multiset of positive integers s={s1,s2,…,sk}s={s1,s2,…,sk}, define the Greatest Common Divisor (GCD) and Least Common Multiple (LCM) of ss as follow:

  • gcd(s)gcd(s) is the maximum positive integer xx, such that all integers in ss are divisible on xx.
  • lcm(s)lcm(s) is the minimum positive integer xx, that divisible on all integers from ss.

For example, gcd({8,12})=4,gcd({12,18,6})=6gcd({8,12})=4,gcd({12,18,6})=6 and lcm({4,6})=12lcm({4,6})=12. Note that for any positive integer xx, gcd({x})=lcm({x})=xgcd({x})=lcm({x})=x.

Orac has a sequence aa with length nn. He come up with the multiset t={lcm({ai,aj}) | i<j}t={lcm({ai,aj}) | i<j}, and asked you to find the value of gcd(t)gcd(t) for him. In other words, you need to calculate the GCD of LCMs of all pairs of elements in the given sequence.Input

The first line contains one integer n (2≤n≤100000)n (2≤n≤100000).

The second line contains nn integers, a1,a2,…,ana1,a2,…,an (1≤ai≤2000001≤ai≤200000).Output

Print one integer: gcd({lcm({ai,aj}) | i<j})gcd({lcm({ai,aj}) | i<j}).ExamplesinputCopy

2
1 1

outputCopy

1

inputCopy

4
10 24 40 80

outputCopy

40

inputCopy

10
540 648 810 648 720 540 594 864 972 648

outputCopy

54

Note

For the first example, t={lcm({1,1})}={1}t={lcm({1,1})}={1}, so gcd(t)=1gcd(t)=1.

For the second example, t={120,40,80,120,240,80}t={120,40,80,120,240,80}, and it’s not hard to see that gcd(t)=40gcd(t)=40.


题意简单不做作:让你求gcd( lcm(a[i],a[j])(i<j) );

暴力是n^2的做法:枚举每一个a[i]和j>i的lcm,存下来再在之间进行gcd,这个枚举O(n^2)了;超时;

优化:

图片挂了

这个式子怎么来的?

假设现在只有a,b,c; 对a来说,求的是gcd_1=( lcm(a,b),lcm(a,c) ); [公式:a*b=lcm(a,b)*gcd(a,b);]

那么转化成 gcd_1=a*gcd( b/gcd(a,b), c/gcd(a,c) );

数字代表被划分的区域(是一个个集合)  a b c代表圆

任意区域重叠的部分就是两个区域所代表的数的公约数

(顺带一提这种方法不能普遍使用 证明这种基础的数论题还是可以的 更深入的就不行了

b/(a,b)就是区域2+5 c/(a,c)就是区域3+5
这两个的最大公约数就是区域5 也就是2+5和3+5的重叠部分就是区域5


附上我问郏同桌的一句话“ b/gcd(a,b)==2+5,这个不是集合的差运算嘛..集合b-集合gcd(a,b)是等价b/gcd(a,b)?还是说这个除法在集合论里面表示集合的差运算”

” 是啊 你就仔细想一下 不是一样的吗 当然深入的话不可能那么形象的就用韦伯图就可以表示出来”


通过图就可以看出 a*gcd( b/gcd(a,b), c/gcd(a,c) )== a*gcd(b,c)/gcd(a,b,c);

再通过图的几何意义发现是lcm(a,gcd(b,c) ) ;


当有n个时,式子化简为gcd_1=lcm(a1,gcd(a2,a3,…an))

以此类推,可得gcd_2,gcd_3….gcd_n

那么答案可表示为 gcd(gcd_1,gcd_2,…gcd_n)

那我们就能通过处理后缀来存求gcd_1途中的gcd(a2,a3,a4,…,an)来达到简化的目的


#include<iostream>
#include<vector>
#include<queue>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn=2e5+10;
typedef long long LL;
LL p[maxn];
LL suf[maxn];
LL gcd(LL a,LL b)
{
	return b?gcd(b,a%b):a;
}
LL lcm(LL a,LL b)
{
	return a/gcd(a,b)*b;
}
int main(void)
{
	LL n;cin>>n;
	for(LL i=1;i<=n;i++)
			cin>>p[i];
	///后缀,用来求gcd_1=lcm(a1,gcd(a2,a3,a4....an))中的gcd(a2,a3,a4,..an); 
	for(LL i=n;i>=1;i--) suf[i]=gcd(suf[i+1],p[i]);
	////反复更新答案来求gcd(gcd_1,gcd_2,gcd_3,...gcd_n)
	LL ans=0;
	for(LL i=1;i<=n;i++)
		 ans=gcd(ans, lcm(p[i],suf[i+1]) );
	cout<<ans<<endl;
	
return 0;
}

猜你喜欢

转载自blog.csdn.net/zstuyyyyccccbbbb/article/details/106167500