数论
关于约数
相亲数:
题目:https://www.luogu.com.cn/problem/P1851
数学中的相亲数,也就是说两个数中任意一个的所有因子(除本身外)之和等于另外一个数。
1.O(n sqrt(n))算法:考虑约数成对出现,注意完全平方数(该方法已经可以AC(76ms))。
int j;
for(register int i=1;i<=100000;i++)
{
for(j=1;j*j<=i;j++)
{
if(i%j==0)
{
pr[i]+=j;
pr[i]+=i/j;
}
}
j--;
if(j*j==i)pr[i]-=j;
pr[i]-=i;
}
2.O(n log(log(n)))算法:筛法优化。(秒啊~~)
for(int i=1;i<=20000;i++)
for(int j=i;i*j<=20000;j++)
pr[i*j]+=i;
一定注意读题,比如这个题就:
1.(6≤S≤18000) ,找出序列号不小于 S。
- A 表示第一个序列号不小于 S 的有“非常好友”的同学,B 是 A 的“非常好友”,而不是:两者都得大于s.
更新:2020.11.12
试题 G:(2019国赛)
G:数正方形(难度:★★★★★
【问题描述】
在一个 N × N 的点阵上,取其中 4 个点恰好组成一个正方形的 4 个顶点,
一共有多少种不同的取法?
由于结果可能非常大,你只需要输出模 109 + 7 的余数。
如上图所示的正方形都是合法的。
【输入格式】
输入包含一个整数 N。
【输出格式】
输出一个整数代表答案。
【样例输入】
4
【样例输出】
20
【数据规模与约定】
对于所有评测用例,2 ≤ N ≤ 1000000。]()
import java.util.Scanner;
public class G {
public static void main(String[] args) {
Scanner scanner=new Scanner(System.in);
int n=scanner.nextInt();
long ans=0;
for(int i=1;i<=n;i++){
ans+=(long)i*(long)i*(long)(n+1-i);
ans%=1000000007;
}
System.out.println(ans);
}
}
数论题目,我们枚举当边长固定的情况下,正方形的边均在最外层正方形的情况。
我们发现,当边长为x时,角在边的正方形的个数为x,如边长为4时有四种情况,
本质就是一个角在大正方形的一条边上来回移动。
所以我们推论当边长为x时,角在边的正方形的个数为x。
另一方面,
大的正方形可以分解成规规矩矩的小正方形,同样我们枚举顶点可以得到小正方形的个数,
同样,小正方形的个数也是有规律的。
1个4乘4的方格可以分成4个3乘3的方格
即2乘2个3乘3方格。
所以我们得出推论
ans[N]=Σ i * i * (n+1-i)
前面 i * i 表示最大边为(n+1-i)的大正方形的个数
试题 C: 切割
本题总分:10 分
【问题描述】
在 4 × 4 的方格矩阵中画一条直线。则直线穿过的方格集合有多少种不同的
可能?
这个里直线穿过一个方格当且仅当直线将该方格分割成面积都大于 0 的两
部分。
//以下代码未完善!!!!!!思路是这个
package no10Guosai;
import java.util.HashSet;
import java.util.Set;
class node{
int x,y;
public node(int x, int y) {
super();
this.x = x;
this.y = y;
}
}
public class C {
static Set<String> set=new HashSet<>();
static node[][] matrix=new node[17][4];
public static void main(String[] args) {
//初始化矩阵的四个点坐标
init();
for (int i = 1; i <=4; i++) {
for (int j = 1; j <=4; j++) {
matrix[(i-1)*4+j][0].x=(j-1);
matrix[(i-1)*4+j][0].y=(i-1);
matrix[(i-1)*4+j][1].x=(j-1+1);
matrix[(i-1)*4+j][1].y=(i-1);
matrix[(i-1)*4+j][2].x=(j);
matrix[(i-1)*4+j][2].y=(i);
matrix[(i-1)*4+j][3].x=(j-1);
matrix[(i-1)*4+j][3].y=(i-1+1);
}
}
work();//依次遍历,依据两点坐标建立二元一次直线方程
System.out.println(set.size());
}
static void init() {
for (int i = 1; i <=16; i++) {
for (int j = 0; j <4; j++) {
matrix[i][j]=new node(0, 0);
}
}
}
static void work() {
for (int i = 1; i <= 16; i++) {
for (int j = 0; j < 4; j++) {
int x1=matrix[i][j].x;
int y1=matrix[i][j].y;
int x2 = 0,y2 = 0;
System.out.println("当前--块"+i+"的第:"+j+"个节点");
for (int k = i; k <=16; k++) {
for (int l = 0; l < 4; l++) {
x2=matrix[k][l].x;
y2=matrix[k][l].y;
//建立方程
if((x2-x1!=0)&&(y2-y1!=0)){
int kk=(y2-y1)/(x2-x1);
int b=y1-kk*x1;
if(kk!=0){
System.out.println(" 与块"+k+"的第:"+l+"个节点对比");
check(kk,b);//检查直线穿过的方框
}
}
}
}
}
}
}
private static void check(int k, int b) {
// System.out.println("k="+k+" "+"b="+b);
String s="";
for (int i = 1; i <=16 ; i++) {//对每个格子
int y_0=k*matrix[i][0].x+b;
int x_0=(matrix[i][0].y-b)/k;
int y_1=k*matrix[i][1].x+b;
int x_3=(matrix[i][3].y-b)/k;
if((y_0>matrix[i][0].y&&y_0<matrix[i][3].y)||
(y_1>matrix[i][1].y&&y_1<matrix[i][2].y)||
(x_0>matrix[i][0].x&&x_0<matrix[i][1].x)||
(x_3>matrix[i][3].x&&x_3<matrix[i][2].x)||
(matrix[i][0].x==x_0&&matrix[i][0].y==y_0&&matrix[i][2].y==y_1&&matrix[i][2].x==x_3)||
(matrix[i][3].x==x_3&&matrix[i][1].y==y_1&&matrix[i][3].y==y_0&&matrix[i][1].y==y_1)
){
s+=i;
set.add(s);
}
}
}
}
trix[i][0].yy_0&&matrix[i][2].yy_1&&matrix[i][2].xx_3)||
(matrix[i][3].xx_3&&matrix[i][1].yy_1&&matrix[i][3].yy_0&&matrix[i][1].y==y_1)
){
s+=i;
set.add(s);
}
}
}
}