冬令营第三天(1.20)

问题A:Birthday Cake

题目链接:UVA10167

题目大意及思路:

给出一个半径为100的蛋糕,上面由2*N个樱桃,直线Ax+By=0恰好将蛋糕分成两半的同时,两边的蛋糕上的樱桃也是相同的。
思路: 暴力,枚举,A,B范围在[-500,500]

AC代码:

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<queue>
#include <vector>
#include<stack>
#include<map>
#include<set>
#include<string>
#include<cstring>
using namespace std;
typedef long long ll;
const int N = 50;
struct point{ //用于记录结构体的坐标 
	int x,y;
};
int main()
{
	int num,left,right,find;//num代表一边樱桃的数量 
	int A=0,B=0;
	point p[2*N+5];
	while(cin >> num && num)
	{
		left = right = 0;
		find = 0;
		for(int i=0; i<num*2; ++i)//输入每个樱桃的坐标 
		{
			cin >> p[i].x;
			cin >> p[i].y;
		}
		for(int i=-500; i < 500; ++i){ // 暴力枚举 
			for(int j=-500; j < 500; ++j)
			{
				left=right=0;
				if(i*j==0) continue; 
				for(int k=0; k<num*2; ++k)
				{
					if(p[k].x > 100 || p[k].y > 100 || p[k].x < -100 || p[k].y < -100 ) continue; //不在蛋糕上 
					if( p[k].x *i + p[k].y *j == 0) break; // 在直线上,不行 
					if( p[k].x *i + p[k].y *j > 0) left++; // 统计左边的数量 
					else right++; //统计右边的数量 
				}
				if(left == right && left + right == num*2){
					A=i;
					B=j;
					find=1;
					break;
				}
			}
			if(find==1) break;
		} 
		cout << A << " "<< B << endl;
	}
	return 0;
}

问题B:Is This Integration ?

题目链接:UVA10209

题目大意:

如图:给出正方形ABCD边长a,分别以正方形的各顶点为园心,a为半径画圆弧,求条纹面积x,星罗面积y,以及剩下的面积z。
1
易知:
x+4y+4z=a* a;(整个正方形形的面积)
x+3y+2z=a* a *π / 4;(1/4圆的面积)
x+2y+z=(π/3-√3/4)a * a;(中间的正三角形及两个弓形)
可以推出:
x=(1 + π / 3 - √3 ) * a * a
y=( π / 12 + √3 / 2 - 1) a * a
z=(1 - √3 / 4 - π / 6 ) * a * a

参考代码:

#include<iostream>
#include<cmath>
using namespace std;
#define PI acos(-1.0)

int main()
{
	double a;
	while (cin >> a)
	{
		double x=a * a * (1 + PI / 3 - sqrt(3.0));
		double y=a * a * (PI / 3 + 2 * sqrt(3.0) - 4);
		double z=a * a * (-2 * PI / 3 + 4 - sqrt(3.0));
		printf("%.3f %.3f %.3f\n",x,y,z);
	}
	return 0;
}

问题C:Simple division

题目链接:UVA10407
题目大意:

给出若干个数,以0表示结束,求出一个整数,这个整数是这些数的相同余数的最大值。
思路: 如果两个不同的数除以一个除数的余数相同,那么两个不同数的差值一定是除数的整数倍。对于此题,先求出原序列的差分序列,然后求出所有非零元素的__gcd(a,b);

参考1:

#include<bits/stdc++.h>
using namespace std;
const int N = 1e6+5;
int f[N];

int main()
{
	int x,a;
	while(cin >> x && x)
	{
		int id=0,k;
		while(true)
		{
			cin >> a;
			if(a==0) break;
			
			f[id++]=a-x;//差分处理 
			x = a;
		}
		for( k=0;f[k]==0;k++);//去除多余的零 
		int g = f[k++];
		for(; k < id; ++k){
			if(f[k]) g=__gcd(g,f[k]);
		}
		cout << abs(g) << endl;
	}
	return 0;
} 

参考2:

其实可以一边输入一边处理,可以不用开差分数组,节省了空间

参考代码:

#include<bits/stdc++.h>
using namespace std;

int main()
{
	int a,x;
	while(cin >> x && x)
	{
		int g=0;
		while(cin >> a && a)
		{
			int d=x-a;
			x = a;
			if(d){ // 差值为0,跳过 
				if(g) g=__gcd(g,d); //求最大值 
				else g=d;
			}
		}
		cout << abs(g) << endl; 
	}
	return 0;
} 

问题D:Euclid Problem

题目链接:UVA10104

题目大意:

题目要求输入两个正整数a和b,要求输出满足ax+by = d(其中d为a与b的最大公约数)这个式子对应的x和y的解

思路:

扩展欧几里得算法(模板…

  • 先来欧几里得算法其实就是辗转相除法求最大公约数

核心代码:gcd(a , b) = gcd(b , a mod b)
int gcd(int a, int b) return b == 0 ? a : gcd(b, a % b);//据说比普通的算法快

  • 扩展欧几里得

定理描述:对于两个不全为0的整数a、b,必存在一组解x,y,使得ax+by==gcd(a,b);
具体代码实现:

int exgcd(int a,int b, int& x, int& y){
   int t,d;
   if(b==0) {
       x=1, y=0;  
   	return a;
   }
   d=exgcd(b,a%b);
   t=x, x=y;
   y=t-(a/b)*y; 
return d;
}

更加具体的证明

好了,回到此题(套模板~~) ,参考代码:

#include<iostream>

using namespace std;

int exgcd(int a, int b, int& x, int& y) {
	if (b == 0) {
		x = 1; y = 0;
		return a;
	}
	int d = exgcd(b, a % b, x, y);
	int tmp = x;
	x = y;
	y = tmp - (a / b) * y;
	return d;
}
int main() {
	int a, b;
	while (cin >> a >> b) {
		int x = 0, y = 0;
		int d = exgcd(a, b, x, y);
		cout << x << ' ' << y << ' ' << d << endl;
	}
	return 0;
}

问题E:Dead Fraction

题目链接:POJ1930

题目大意:

给出一个小数,确保是无限循环效数,把无限循环小数变最简分数,但不确定循环节是哪几位,要求输出分母最小的分数。
思路: 日本野口哲典在《天哪!数学原来可以这样学》中介绍了如何将循环小数转化成分数的方法,现介绍如下:
1.循环小数0.7272……循环节为7,2两位,因此化为分数为72/99=1/8.即有几位循环数字就除以几个9。又如>0.123123……循环节为1,2,3三位,因此化为分数为123/999=41/333.这种方法只适用于从小数点后第一位就开循环的小数,如果不是从第一位就开始循环的小数,必须用下面的方法。

2.循环小数0.41666……先把0.41666……乘以100得41.666……,可以理解为41+0.666……,所以写成分数为41+6/9=41+2/3=125/3.因为开始乘以了100,所以再除以100,即125/3÷100=125/300=5/12.

综上可知公式:

分子:不循环部分*10^(循环节数字个数)+循环节
分母:10^(不循环部分数字个数) *(10^(循环节数字个数)-1)
最后还要记得约分

参考代码:

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<queue>
#include <vector>
#include<stack>
#include<map>
#include<string>
#include<cstring>
using namespace std;
typedef long long ll;
ll Tpow[10]; 
ll gcd( ll a ,ll b) {
	return b==0?a:gcd(b,a%b);
}

void init()
{
	int i;
	Tpow[0]=1;
	for(int i = 1; i < 10; i++){
		Tpow[i] = Tpow[i-1]*10;
	}
}

int main()
{
	char str[200];
	ll ans,a,b,c,temp,mina,minb,t,i;
	init();
	while(~scanf("%s",str)){
		if(str[0] == '0' && strlen(str) == 1) break;
		ans = 0;
		t = 0;
		mina = -1, minb = -1;
		for( i = 2; str[i] != '.'; i++){
			ans = ans*10+str[i] - '0';
			t++;
		}
		for(i = t; i > 0; i--){
			c = ans;
			b = Tpow[t-i]*(Tpow[i] - 1);
			c = c/Tpow[i];
			a = ans-c;
			temp = gcd(a,b);
			if(b/temp<minb || mina == -1){
				mina = a/temp;
				minb = b/temp;
			}
		}
		cout << mina << "/"<< minb << endl;
	}
	return 0;
}

问题F:What is the Probability ?

题目链接:UVA10056

题目大意:

从1-n轮回掷骰子,每个人每次有p的概率赢,求出第m个人赢的概率。

概率问题:

在这里插入图片描述

参考代码:

#include<iostream>
#include<cmath>
using namespace std;
int s, x, i;
double p;
double ans;
int main() {
	cin >> s;
	while (s--) {
		cin >> x >> p >> i;
		if(p==0) ans = 0;
		else ans = pow(1 - p, i - 1) * p * (1.0 / (1 - pow(1 - p, x)));
		printf("%.4f\n", ans);
	}
	return 0;
}

问题G:Coin Toss

题目链接:POJ3440
题目大意:

给出了一个n*m的格子,每个格子的边长为t,随意抛一枚硬币并保证硬币的圆心在格子里或格子边上,硬币的直径为c,求硬币覆盖格子的个数的概率。
思路:仔细一想,这不是高中的几何概型概率题嘛!根据分别覆盖1,2,3,4个格子时圆心分部的面积比上总面积就是答案。

参考代码:

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cmath>
using namespace std;
const double PI=acos(-1.0),eps=1e-8;
int main()
{
    int x,cnt=0;
    cin>>x;
    while(x--){
        double n,m,t,c,A[5];
        scanf("%lf%lf%lf%lf",&n,&m,&t,&c);
        A[0]=t*t*n*m;//棋盘面积 
        A[2] = c*(t-c)*(2*m*n-n-m)+c*(c/2.0)*(2*n+2*m-4);
		A[4] = (m-1)*(n-1)*(PI*c*c)/4.0;
		A[3] = (m-1)*(n-1)*c*c-(m-1)*(n-1)*(PI*c*c)/4.0;
		A[1] = A[0]-A[2]-A[3]-A[4];
        printf("Case %d:\n",++cnt);
        for(int i=1;i<=4;i++)
            printf("Probability of covering %d tile%s = %.4lf%%\n",i,(i==1)?" ":"s",A[i]/A[0]*100.0);
        printf("\n");
    }
    return 0;
}

问题H:498-bis

题目链接:UVA10268
题意:

多项式求值,给出一个多项式,求出这个多项式的导数,并将x带入求值

思路:

听课是说递推式:A(i+1)=A(i)∗x+ai
还不会证明~~~>=<

参考代码:

#include<iostream>
#include<cmath>
using namespace std;

int main(){
	int x,a;
	char c;
	while(~scanf("%d",&x)){
		int sum=0,ans = 0;
		while(~scanf("%d",&a)){
			ans = ans*x+sum;
			sum = sum*x+a;
			scanf("%c",&c);
			if(c=='\n') break;
		}
		cout<<ans<<endl;
	}
}

总结:

  • 数论知识太薄弱了~
  • 一听就会,一做就废(太真实了;;
  • 以后要常回来看看这些数论基础(摸鱼摸鱼QwQ)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

W⁡angduoyu

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

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

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

打赏作者

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

抵扣说明:

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

余额充值