国庆训练10.3

the first one

tag:数论

题面

[HAOI2008]圆上的整点
时间限制:10秒 内存限制:162MB

题目描述
  求一个给定的圆(x2+y2=r2),在圆周上有多少个点的坐标是整数。
输入
  只有一个正整数r,r<=2000 000 000
输出
  整点个数
样例输入

4

样例输出

4

思路

题解
  很简洁的一道题 ,这是我做过所有题里题面最短的一道,也是题意最易理解的一道。但是真正做起来就没那么容易了。这是一道数论题,首先,根据圆的对称性,只需要求处第一象限满足条件的点个数,然后*4,再加上坐标轴上四个满足条件的点就可以了。第一象限满足条件的点,暴力的做法是枚举区间[1,r)内所有的点,判断其是否满足圆的方程,但是由于r最大为2e9,显然会T;所以采取缩小枚举范围的方式进行求解。利用数论基础知识,进行推导从而达到缩小枚举范围的目的,具体推导过程如下:
  x2+y2=r2 ⇒ \Rightarrow x2=r2-y2=(r+y)*(r-y);
  令d=gcd((r+y),(r-y)),A= r + y d \frac {r+y}{d} dr+y,B= r − y d \frac {r-y}{d} dry则gcd(A,B) ≡ \equiv 1
  又,x2=d2*A*B
   ∵ \because x2、d2为完全平方数且gcd(A,B) ≡ \equiv 1
   ∴ \therefore A,B也为完全平方数
  令A=a2,B=b2,则a2+b2= 2 ∗ r d \frac {2*r}{d} d2r
  通过枚举d ∈ \in [1, 2 ∗ r \sqrt{2*r} 2r ]&d为整数,并使得2*r/d为整数,(d有两种情况:d =d or 2*r/d。分别进行讨论)然后再枚举a(设a<b),a ∈ \in [1, 2 ∗ r / 2 ∗ d \sqrt{2*r/2*d} 2r/2d ],求出b,在b为正整数的情况下,验证A,B是否满足:A ≠ \ne =B&&gcd(A,B) ≡ \equiv 1,求出满足条件的点个数就欧克了。

源码

#include<iostream>
#include<cmath>
#include<algorithm>
using namespace std;
typedef long long ll;
int main(){
	ll r,r2;
	cin>>r;r2=2*r;
	ll a,A,B,c,d,ans=4,cnt=0;
	double b;
	for(d=1;d*d<=r2;d++){
		if(r2%d==0){
		c=d;
		ll am=r/c;
		for(a=1;a*a<=am;a++){
			b=sqrt(1.0*r2/d-a*a);
			if(b==(int)b){
				A=a*a;B=b*b;
				if(A!=B&&__gcd(A,B)==1) cnt++;
			}
		}
		c=r2/d;
		if(c!=d){
		    am=r/c;
		    for(a=1;a*a<=am;a++){
			  b=sqrt(1.0*d-a*a);
			   if(b==(int)b){
				A=a*a;B=b*b;
				if(A!=B&&__gcd(A,B)==1) cnt++;
			}
		}	
		}	
		} 
	}
	ans+=4*cnt;
	cout<<ans;
	return 0;
} 

the second one

tag:二分图匹配,匈牙利算法,递归

题面

[ZJOI2007]矩阵游戏
时间限制:10秒 内存限制:162MB

题目描述
  小Q是一个非常聪明的孩子,除了国际象棋,他还很喜欢玩一个电脑益智游戏——矩阵游戏。矩阵游戏在一个N*N黑白方阵进行(如同国际象棋一般,只是颜色是随意的)。每次可以对该矩阵进行两种操作:行交换操作:选择矩阵的任意两行,交换这两行(即交换对应格子的颜色)列交换操作:选择矩阵的任意行列,交换这两列(即交换对应格子的颜色)游戏的目标,即通过若干次操作,使得方阵的主对角线(左上角到右下角的连线)上的格子均为黑色。对于某些关卡,小Q百思不得其解,以致他开始怀疑这些关卡是不是根本就是无解的!!于是小Q决定写一个程序来判断这些关卡是否有解。
输入
  第一行包含一个整数T,表示数据的组数。接下来包含T组数据,每组数据第一行为一个整数N,表示方阵的大小;接下来N行为一个N*N的01矩阵(0表示白色,1表示黑色)。
输出
输出
  输出文件应包含T行。对于每一组数据,如果该关卡有解,输出一行Yes;否则输出一行No。
样例输入

2
2
0 0
0 1
3
0 0 1
0 1 0
1 0 0

样例输出

No
Yes

提示
【数据规模】
对于100%的数据,N ≤ 200

思路

题解
  本来想用线性代数知识中矩阵的秩来进行求解,可是写到一半发现思路不对
  这是一道二分图匹配的问题,可以用匈牙利算法进行求解。
  匈牙利算法简介:
  假设有n个男孩和n个女孩,其中有若干对男女互有好感(一个男or女孩可以对0个或多个女or男孩有好感),我们的任务是:进行男女匹配,看最终是否可以使得所有人都结为恋人……
  我们的算法是这样的:依次给所有男生进行分配女朋友 (虽然现实中不可能这样哈哈哈),看最终是否每个男生都能抱得美人归。首先,给1号男生分配女朋友,选最近的一个与之互有好感且未有归属的女生给之,然后给2号男生分配,……出现不能给男生分配女朋友的情况后就进行调度(关键之处),调度方法:从第一个该与该男生有好感的女生开始,看是否可以给其所属男朋友更换女朋友,以把这给女生让给我们可怜的没有女朋友的男生,看其是否可以更换就又要进行调度(递归),依次对该没有女朋友的男生互有好感的女生进行调度,直到可以分配女朋友;若最终调度失败,则不能为该男生分配女朋友,整个任务失败。
  我们这道题就可以套用上述算法,将行看为男生,列看为女生,a[i][j]=1表示男生i和女生j互有好感,只要能为所有行分配为1的列就可以实现主对角线全一的目标,否则不能实现。具体实现可以看代码再进行体会。

源码

/******二分图匹配,匈牙利算法,递归******/ 
#include<iostream>
#include<cstring>
#define mem(a,b) memset(a,b,sizeof(a))
using namespace std;
const int N=205;
int a[N][N],vis[N],d[N],n;
bool fun(int x){//对第x行进行分派,返回分派结果 
	
	int i;
	
	for(i=1;i<=n;i++){
		if(a[x][i]&&!vis[i]){//a[x][i]为1可分派,并且vis[i]为0即没访问过 
			vis[i]=1;//修改vis[i]状态,表示已访问过 
			if(d[i]==-1||fun(d[i])){
//精髓所在……,调度数组d,若为-1表示未分派,可用;否则调用fun函数进行调度 
				d[i]=x;return true;
			}
		}
	}
	
	return false;
} 
int main(){
    ios::sync_with_stdio(0);
    cin.tie(0);cout.tie(0);
    int T;
    cin>>T;
    while(T--){
    	mem(a,0);mem(d,-1);
    	int i,j;
		cin>>n;
    	for(i=1;i<=n;i++){
    		for(j=1;j<=n;j++){
    			cin>>a[i][j];
			}
		}
		
		for(i=1;i<=n;i++){//对所有n行进行分派,只要有一行分派失败则整体失败 
			mem(vis,0);
			if(!fun(i)) break; 
		} 
		i<=n?cout<<"No\n":cout<<"Yes\n";
		
	}
	return 0;
} 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值