牛客挑战赛60题解A-C

 

A题:第三心脏

 

 由gcd的性质,我们可以得到:

设gcd(a,b)=x;

a=k*x;

b=t*x;

c=w*x;

且k,t,w三个数互质

因为c是a的倍数:w=n*k;(n>=2)

所以c=n*k*x;

现在需要使得gcd(b,c)即gcd(t*x,n*k*x)=x;

也就是说要让gcd(t,n*k)=1;

即 t 和 n*k 互质

因为k 和 t 互质

所以只需要n和t互质即可

所以就for(n=2;;n++)

直到gcd(n,t)==1;

输出n*k*x;

 1 #include"bits/stdc++.h"
 2 using namespace std;
 3 #define int long long
 4 int gcd(int a,int b){
 5     return b==0?a:gcd(b,a%b);
 6 }
 7 signed main(void){
 8     int t;cin>>t;
 9     while(t--){
10         int a,b;
11         scanf("%lld%lld",&a,&b);
12         int gg=gcd(a,b);
13         int k=a/gg;
14         int t=b/gg;
15         int w;
16         for(int i=2;;i++){
17             w=i*k;
18             if(gcd(w,t)==1){
19                 break;
20             }
21         }
22         printf("%lld\n",w*gg);
23         
24     }
25     return 0;
26 }

 

B题:尖端放电

 

 

一开始就觉得暴力枚举每两个尖塔的时间复杂度O(k^2) 都10的10次方了,肯定是不行的。。。

结果可以。。。

那就很简单了,枚举所有两个尖塔,得到中点。(还是觉得很奇怪这都能过??)

 

 

 1 #include"bits/stdc++.h"
 2 using namespace std;
 3 #define maxn 100010
 4 inline int read()
 5 {
 6     int x = 0;char c = getchar();
 7     while (c < '0' || c>'9') c = getchar();
 8     while (c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();
 9     return x;
10 }
11 struct xy{
12     int x;
13     int y;
14 }a[maxn];
15 map<pair<double,double>,int>ump;
16 int main(void){
17     int t;cin>>t;
18     while(t--){
19         int n,m,k;
20         cin>>n>>m>>k;
21         for(int i=1;i<=k;i++){
22             cin>>a[i].x>>a[i].y;
23            // a[i].x=read();a[i].y=read();
24         }
25         int flag=0;
26         for(int i=1;i<=k;i++){
27             for(int j=i+1;j<=k;j++){
28                 double xx,yy;
29                 xx=((double)a[i].x+(double)a[j].x)/2;
30                 yy=((double)a[i].y+(double)a[j].y)/2;
31                 pair<double,double>temp;temp.first=xx;temp.second=yy;
32                 ump[temp]++;
33                 if(ump[temp]>=2){
34                     printf("YES %.1lf %.1lf\n",xx,yy);
35                     flag=1;
36                     break;
37                 }
38             }
39             if(flag)break;
40         }
41         if(flag==0)printf("NO\n");
42         ump.clear();
43     }
44     return 0;
45 }

 

c题:格点染色

 

 

 

考虑函数dp(x)代表前x格的全部染成黑色的顺序种类

 1.当前x-1的格子都染黑了,在前x的格子中最后染色的是第x格时候,因为此时只有一种选择,故:dp(x)=dp(x-1)

2.接下来,我们由1.大概能知道,这题对 每个dp(x)需要由dp(x-1)推导出,所以考虑dp(x-1)和dp(x)的关系。

考虑一般的dp(x-1)到dp(x)是走到x-1格子,然后走到下一格x,将其染色,完成操作。

但是我们可不可以在原先【染dp(x-1)】的【最后一个格子p】的步骤时候,选择不去染,然后先去染x格,然后再跳回来,【最后染第p个格子】呢?(为了理解局限为最后一个格子p)

***因为染完x,我们会跳到小于x的ax格子去,所以如果p属于[ax,x-1]区间,我们就可以由p的前一个染色的格子y 所跳 ay开始走,走过p,走到x,然后染色,跳到ax,再继续走到p的时候,以p作为dp(x)的最后一个染色格子,完成dp(x)的操作。

其中路径:

y<=x-1

ay<=p;

p: [ax,x-1]

从左至右数轴的点(其中一种可行的方法,并不止这一种):ay,ax,y,p,x-1,x

各位可以以上面的路径点画出dp(x-1)的运行操作,然后利用上述操作,完成dp(x)的操作,会很清晰。

扩展推广一下,其实p点并不局限为最后一个染色点,可以手动模拟试试。

在原先染dp(x-1)的方案的基础上,对每个方案,都对最后一次染色改变选择,所以dp(x)是由每个dp(x-1)的可能性基础上,然后选择某个点p,p点只要属于[ax,x-1]即可。故此时在原先的基础上,多了x-1-ax+1种选择可能,故dp(x)=dp(x-1)*(x-1-ax+1)

综上两种可能,我们可以得到dp(x)=dp(x-1)*(x-1-ax+1)+dp(x-1)=dp(x-1)*(x-ax+1)。

由此得到res*=(i-ai+1) , i:[1,n]。

时间复杂度O(n)

 1 #include<iostream>
 2 using namespace std;
 3 const int mod=1e9+7;
 4 int main(void){
 5     int n;
 6     cin>>n;
 7     long long res=1;
 8     for(int i=1;i<=n;i++){
 9         long long x;scanf("%lld",&x);
10         x=i-x+1;
11         res=(x*res)%mod;
12     }
13     cout<<res<<endl;
14     return 0;
15 }

任重道远

 

posted @ 2022-05-16 11:57  Tiachi  阅读(50)  评论(0)    收藏  举报