ACM的训练计划

文章介绍了处理关于时钟旋转和数学求解的问题,涉及三指针运动、旋转角度计算及寻找具有特定因子条件的最小数字。
摘要由CSDN通过智能技术生成

题目链接:牛客竞赛_ACM/NOI/CSP/CCPC/ICPC算法编程高难度练习赛_牛客竞赛OJ (nowcoder.com)

下面是我做的两个题:(边敲代码编写报告,不然一直敲代码有点累)

一.

Cuber QQ likes observing the clock when he is bored.
Cuber QQ喜欢在无聊的时候观察时钟。

This time, Cuber QQ buys a kooky clock, the clock has three hands. Unlike ordinary clocks, the three hands of this clock are connected one by one, i.e., the first hand is at the innermost position, and its rotating center is the center of the dial. The rotating center of the second hand is the end of the first hand (that is, with the rotation of the first hand, the rotating center of the second hand will change); similarly, the third hand is rotating around the end of the second hand.


这一次,Cuber QQ买了一个古怪的时钟,时钟有三根指针。与普通时钟不同,该时钟的三根指针是一一对接的,即第一针在最里面的位置,其旋转中心是表盘的中心。秒针的旋转中心是第一针的末端(即随着第一针的旋转,秒针的旋转中心会发生变化);同样,第三只指针绕着第二只指针的末端旋转。


The lengths of the three hands are l1,l2l_1,l_2l1​,l2​ and l3l_3l3​ respectively, and their rotating speed is also different, the time required for three hands to rotate in a 360-degree is t1t_1t1​ second, t2t_2t2​ second and t3t_3t3​ second.


三只手的长度分别是 l1,l2l_1,l_2l1​,l2​ 和 l3l_3l3​ ,它们的转速也不同,三只手 360 度旋转所需的时间是 t1t_1t1​ 秒、 t2t_2t2​ 秒和 t3t_3t3​ 秒。

Cuber QQ assumes that the center of the clock is the origin of the axes and the end of three hands are at (0,l1)(0,l_1)(0,l1​), (0,l1+l2)(0,l_1+l_2)(0,l1​+l2​) and (0,l1+l2+l3)(0,l_1+l_2+l_3)(0,l1​+l2​+l3​) at begining.


Cuber QQ 假设时钟的中心是轴的原点,三根指针的末端位于 (0,l1)(0,l_1)(0,l1​) 和 (0,l1+l2)(0,l_1+l_2)(0,l1​+l2​) (0,l1+l2+l3)(0,l_1+l_2+l_3)(0,l1​+l2​+l3​) 的起点。


He now wants to know the position of the end of the third hand after the hands of the clock have rotated TTT seconds.


他现在想知道时钟指针旋转 TTT 秒后第三针末端的位置。

输入描述:

The first line contains one integer TTT (0≤T≤10000\le T\le 10000≤T≤1000), which denotes the times the three hands have rotated.

The second line contains three integers l1,l2l_1,l_2l1​,l2​ and l3l_3l3​ (1≤l1,l2,l3≤10001\le l_1,l_2,l_3 \le 10001≤l1​,l2​,l3​≤1000), denotes the length of each hand.

The third line contains three integers t1,t2t_1,t_2t1​,t2​ and t3t_3t3​ (1≤t1,t2,t3≤10001\le t_1,t_2,t_3 \le 10001≤t1​,t2​,t3​≤1000), denotes the time of each hand required to rotate in a 360-degree.

第一行包含一个整数TTT(0≤T≤10000\leT\le10000≤T≤1000),它表示三只手旋转的时间。第二行包含三个整数l 1,l2l_1,l_2l1​,l2​和l3l_3l3​(1≤l1,l3≤10001\le l_1,l_2,l_3\l_1,l_2,l_3\10001≤l1​,l2​,l3​≤1000),表示每只手的长度。第三行包含三个整数t 1,t2t_1,t_2t1​,2​和t3t_3t3​(1≤t1,t2,t3≤10001\le t_1,t_2,t_3\t_1,t_2,t_3\10001≤t1​,2​,t3​≤1000),表示每只手以360度旋转所需的时间。

输出描述:

Print two numbers to denote the position of the third hand is (x,y)(x,y)(x,y).

Your answer is considered correct if its absolute or relative error does not exceed 10−610^{-6}10−6.

Formally, let your answer be aaa, and the jury's answer be bbb. Your answer is accepted if and only if ∣a−b∣max⁡(1,∣b∣)≤10−6\frac{|a - b|}{\max{(1,|b|)}} \le 10^{-6}max(1,∣b∣)∣a−b∣​≤10−6.

示例1

打印两个数字,表示第三只手的位置为(x、y)(x、y)(x、y)。如果您的绝对误差或相对误差不超过10−610^{-6}10−6,则您的答案被认为是正确的。正式上,让你的回答是aaa,陪审团的回答是bbb。如果且仅当∣a−b∣max⁡(1,∣b∣)≤10−6\frac{|a-b|}{{\max{(1,|b|)}}\le10^{-6}max(1,∣b∣)∣a−b∣​≤10−06。 示例1

输入

2

1 2 3

3 2 1

输出

-0.8660254038 4.5000000000

  1. 理解题意
  2. 尝试用输入的数据算出输出的数据
  3. 计算无误,开始思考需要的库函数、容器、实现过程
  4. 写代码

  1. 这是一个奇怪的钟表,它有3个指针,一个指针连在另外一个指针后面,就这样三个不断连接在一起旋转,其中最开始的指针位置的中心在0,0.转动后得到结果
  2. 对于给出的数据,我们可以得到旋转的时间,指针的长度,指针旋转360度需要的时间。

因此我们可以计算出最后的指针在的末端位置,假设先算第一个指针的末端位置,再算第二根指针的末端位置,第二以第一根指针的末端为中心,再算第三根指针的位置,它以第二根指针的末端为中心。最后推算得出与实例输出相同的结果。

 

3.通过上面推算,我们可以发现我们需要用到sin,cos,π等这些。而且对于三根指针最后的末端的位置,只要通过相加每次转动后的位置相加就可以了(简而言之,三根指针没有顺序,无论那个在中间,结果都一样,因此可以相加),对于时间,长度都可以用数组存储,因为在输入数据时它们是一一对应每个指针的,后面计算很方便。

4.编写代码:

//旋转2次,长度为1,2,3 旋转的时间3 2 1

//每次计算三根指针末端的位置

#include<bits/stdc++.h>

using namespace std;

double T;

double t[4],l[4];

const double pi=acos(-1.0);

int main()

{

    cin>>T;

    for(int i=1;i<=3;i++)

        cin>>l[i];

    for(int i=1;i<=3;i++)

        cin>>t[i];

    double o[4],x[4],y[4];

    for(int i=1;i<=3;i++)

    {

        o[i]=T*2*pi/t[i];//角度大小

        x[i]=l[i]*sin(o[i]);//求出x的坐标

        y[i]=l[i]*cos(o[i]);

    }

    printf("%.10lf %.10lf\n",x[1]+x[2]+x[3],y[1]+y[2]+y[3]);//末端坐标等于三根指针相加

}

二、 

Cuber QQ is finding the minimal interesting number. An interesting number xxx satisfies:

Cuber QQ正在寻找最小的有趣的数字。一个有趣的数字xxx满足:

  • xxx is a positive integer;
  • xxx has at least eight factors;
  • The difference between any two different factors of xxx is not less than nnn.

xxx是一个正整数; xxx至少有八个因素; xxx的任意两个不同因素之间的差异不小于nnn。


Now, Cuber QQ will give you nnn, and ask you to find the least interesting number.

现在,Cuber QQ会给你nnn,并让你找到最不有趣的数字。

输入描述:

The first line contains an integer TTT (1≤T≤10001\le T\le 10001≤T≤1000), representing the number of test cases.

第一行包含一个整数TTT(1≤T≤10001\leT\le10001≤T≤1000),表示测试用例的数量。

The following TTT lines, each line contains an integer nnn (1≤n≤1000001\le n\le 1000001≤n≤100000).

以下的TTT行,每行包含一个整数nnn(1≤n≤1000001\len\le1000001≤n≤100000)。

输出描述:

For each test case, output an integer representing the answer.

对于每个测试用例,输出一个表示答案的整数。

示例1

输入

3

1

2

3

输出

24

105

935

  1. 理解题意,明白题目的各个参数

2.尝试用输入的数据算出输出的数据

3..计算无误,开始思考需要的库函数、容器、实现过程

4.写代码

1.它让我们去寻找一个数,是最不有趣的数,我们根据它的定义去思考有趣的数,它有8个因子,不为负数,差距大于n(n是我们每次给的数据),直接去寻找数不太方便,这次我们从输出给的数据去思考进行反推。首先24?它的因子有1,24,2,12,3,8,4,6.刚好8个,而且每个因数的最小差是2(即6-4=2),2大于输入给的1.对于第二个数据105,它的因子有?嘶,有点不好直接算,不怕我们用代码算。那么我们就需要一个算因数的代码:

#include<bits/stdc++.h>  
using namespace std;  
int n;   
vector<int> vec;  
  
int js(int x){  
    int ans=0;  //计数器  
    for(int i=1; i*i<=x; i++){  //循环到sqrt(x),不用函数,可以快一点;  
        if(x%i==0){   // i 是x的因数;  
            ans++;  
            vec.push_back(i);  
            if(i*i != x){ //特判一下,避免完全平方数被重复添加;  
                ans++;  
                vec.push_back(x/i);  
            }  
        }  
    }  
    return ans;  
}  
  
int main(){  
    cin>>n;  
    int m=js(n);  
    cout<<m<<endl;  // 在输出结果前最好添加一个换行符  
    //输出n的因数   
    for(int i=0; i<vec.size(); i++) cout << vec[i] << " ";  
    cout << endl;  // 在输出因数列表后也添加一个换行符  
    return 0;  
}

对于24,它得到1 24 2 12 3 8 4 6,对于105,它得到1 105 3 35 5 21 7 15,对于935,它得到1 935 5 187 11 85 17 55。

做到这里,可能你不清楚我在做什么,我在反证,现在我们继续根据上面计算因数的代码把它进行修改,让它输出1到1000的因数个数大于8,的数,看看是否可以直接用修改后的代码作为AC的代码。

可以看到我们得到了很多数,现在我们仅仅是满足了第一个条件和第二个条件(正整数和大于8),对于其他条件,怎么使得输入1得到24,输入2得到105,输入3得到935,也就是第三个条件(x的任意两个不同因素之间的差异不小于n。)

哈哈,经过我时长长达两年半的观察,我发现每对因数(也就是1*24=24,1和24算一对)每对开始的时候1 24 2 12 3 8 4 6(24的因数),红色的它们的差值大于等于1。1 105 3 35 5 21 7 15(105的因数)红色的它们的差值大于等于2。

1 935 5 187 11 85 17 55(935的因数)红色的它们的差值大于等于3。

偶吼吼,其他的数似乎没有这样的规律呢,那事不宜迟,GOGOGO

那么我们怎么得到红色的数呢,相信聪明的你已经发现了

    vec.push_back(i);  
            if(i*i != x){ //特判一下,避免完全平方数被重复添加;  
                ans++;  
                vec.push_back(x/i);  
            }  

 

在因数判断的这里的两次插入,前一次插入就是红色,第二次特判就是黑色,我们把它放入两个不同的数组不就可以了,取名字为vec1,vec2。我们判断vec1的数是否差值大于n,应该就差不多了。

最后经过修改和验证的代码:

#include<bits/stdc++.h>  
using namespace std;  
int num;   
vector<int> vec1,vec2;  
  
bool js(int x){  
    int ans=0;  //计数器  
   	bool flag = true;
    for(int i=1; i*i<=x; i++){  //循环到sqrt(x),不用函数,可以快一点;  
        if(x%i==0){   // i 是x的因数;  
            ans++;  
            vec1.push_back(i);  
            if(i*i != x){ //特判一下,避免完全平方数被重复添加;  
                ans++;  
                vec2.push_back(x/i);  
            }  
        }  
    } 
	if(ans>=8){
		for(int i=0;i<vec1.size()-1;i++){//判断差值是否大于num 
			if(vec1[i+1]-vec1[i] < num ){
				flag = false;
			}
		}
		if(flag) return true;
		else false;
	} 
	return false; 
}  
  
int main(){  
	int T;
	cin >> T;
	ios::sync_with_stdio(0),cin.tie(0),cout.tie(0); 
    while(T--){
    	cin >> num;
    	for(int j=1;j<=1000;j++)  
   		 {
   	 		vec1.clear();
   	 		vec2.clear();
    		if(js(j)){
    			cout << j << endl;
    			break;
			}
		}
	}
    return 0;  
}

也是和事例一样了好吧,直接去提交。

呜呜呜暴力解决不了一切,还是看看题解吧。 

题解:看了题解才发现原来不是暴力没有出路,是他喵的出题人!不知道你们有没有发现:1 105 3 35 5 21 7 15(105的因数)1 935 5 187 11 85 17 55(935的因数) 红色的都是素数,对于24(也就只有24是特例!!!),看了这个之后,我真的无言以对,下面的代码是根据我敲得代码更改的,我们只需要判断它红色的是否为素数(就可以快速判断是否满足提议了,24是个特例)

因此这就是我为什么说还需要一个观察能力强的队友,真的有了之后,真的可以定乾坤。

下面是AC代码:

#include<bits/stdc++.h>  
using namespace std;  
int num;   
vector<int> vec1,vec2;  
bool judge(long long a) {//判断素数
    if(a == 1) return 1;
    if(a == 2 || a == 3) return 1;
    if(a%6 != 1 && a%6 != 5) return 0;
    int sqrtA = sqrt(a);
    for(int i = 5; i <= sqrtA; i += 6) {
        if(!(a%i)|| !(a%(i+2))) return 0;
    }
    return 1;
}
bool js(int x){  
    int ans=0;  //计数器  
   	bool flag = true;
    for(int i=1; i*i<=x; i++){  //循环到sqrt(x),不用函数,可以快一点;  
        if(x%i==0){   // i 是x的因数;  
        	if(!judge(i)) return false;
            ans++;  
            vec1.push_back(i);  
            if(i*i != x){ //特判一下,避免完全平方数被重复添加;  
                ans++;  
                vec2.push_back(x/i);  
            }  
        }  
    } 
	if(ans>=8){
		for(int i=0;i<vec1.size()-1;i++){//判断差值是否大于num 
			if(vec1[i+1]-vec1[i] < num ){
				flag = false;
			}
		}
		if(flag) return true;
		else false;
	} 
	return false; 
}  
  
int main(){  
	int T;
	cin >> T;
	ios::sync_with_stdio(0),cin.tie(0),cout.tie(0); 
    while(T--){
    	cin >> num;
    	if(num==1){
    		cout << 24 << endl;
    		continue;
		}
    	for(int j=1;j<=100000;j++)  
   		 {
   	 		vec1.clear();
   	 		vec2.clear();
    		if(js(j)){
    			cout << j << endl;
    			break;
			}
		}
	} 
}

大部分都是直接暴力的,比较好理解,不会暴力就看看,不懂的问我。

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

years_GG

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值