数据结构专题系列 基础篇-2 数论(上)

数据结构专题系列 基础篇-2 数论(上)

--------------------------------------------------------------------------------

题目传送门

洛谷数论 入门组
洛谷数论 普及-组
--------------------------------------------------------------------------------
更多详见>>

OJ题解系列 目录导航帖

--------------------------------------------------------------------------------

这里是数据结构专题系列 基础篇-2 数论(上)
数论是一个大家庭,涵盖了几乎所有数学和算法相关的问题,这其中包括了数列、众数、平均数、中位数、Fibonacci、进制转换、康托展开、逆康托展开、方程式以及数论与其他算法的结合体等等,让我们一起走进数论的世界,一探其中的奥秘。
本章主要涵盖了数论的基础题系列,题目可由上面的传送门获得,想要敲开数论的大门,必须先打好基础。正所谓九层之台,始于垒土;千里之行,始于足下!

本章一共36+75题,推荐先花若干时间学明白数学在算法中的思想,然后分4-8周完成习题,这样有助于巩固所学知识!
习题数量较多,难度不会过大,但这对数论、数学知识打基础至关重要!
更多内容详见 OI WIKI
接下来就是题解部分了,每道算法题都标注有对应的算法标签,对于那些易错、较难或是测试点比较特殊的题目会着重标注,本章推荐的题目有:

P2026 求一次函数解析式计算几何
P2368 EXCEEDED WARNING B数论 平方数
P2067 Cytus-Holyknight计算几何
P1497 木牛流马排列组合
P1595 信封问题数论 DP
P1010 [NOIP1998 普及组] 幂次方数论 DFS
P1211 [USACO1.3]牛式 Prime Cryptarithm数论 枚举
P1258 小车问题数论 方程
P6746 『MdOI R3』Operations数论
P5657 [CSP-S2019] 格雷码数论 DFS
P1932 A+B A-B A*B A/B A%B Problem数论 高精
P1327 数列排序数论 排序
P4122 [USACO17DEC]Blocked Billboard B数论 模拟
P1326 足球数论
P1348 Couple number数论 枚举
P1889 士兵站队数论 中位数
P2719 搞笑世界杯数论 DP

--------------------------------------------------------------------------------

模板003 高精度算法模板-加/减/乘/除/取余

这里给出高精度算法的模板
模板不要求死记硬背,但要求根据算法的原理进行掌握,任何算法明确总体的思路一定是第一位的!

#include<bits/stdc++.h>
using namespace std;
const int maxn = 2e4+5;			//数组大小 
int a[maxn];					//输入数字1(>0)
int b[maxn];					//输入数字2(>0)
int pplus[maxn];				//加法结果 
int mminus[maxn];				//减法结果 
int muti[maxn];					//乘法结果 
int Ta[maxn];					//被除数、除法取余结果 
int Tb[maxn];					//除数 
int divide[maxn];				//除法结果 
string s1,s2;					//输入数1、数2 

void init(){					//初始化函数 
	cin >> s1 >> s2;
	int len1 = s1.size();
	int len2 = s2.size();
	for(int i=0;i<len1;i++){
		a[len1-i-1] = s1[i] - '0';
	}	
	for(int i=0;i<len2;i++){
		b[len2-i-1] = s2[i] - '0';
	}
} 

void add(int a[],int b[],int pplus[]){
	int jw = 0;
	int len1 = s1.size();
	int len2 = s2.size();
	for(int i=0;i<max(len1,len2);i++){
		pplus[i] = a[i] + b[i] + jw;
		jw = pplus[i] / 10;
		pplus[i] %= 10;
	}
	
	if(jw){
		pplus[max(len1,len2)] = jw;
		for(int i=max(len1,len2);i>=0;i--){
			printf("%d",pplus[i]);
		}
		printf("\n");
	}else{
		for(int i=max(len1,len2)-1;i>=0;i--){
			printf("%d",pplus[i]);
		}
		printf("\n");
	}
}

void minu(int a[],int b[],int mminus[]){
	bool f_minus = true;
	int len1 = s1.size();
	int len2 = s2.size();
	if(len2>len1){
		f_minus = false;
	}else if(len2 == len1){
		for(int i=len2-1;i>=0;i--){
			if(a[i]<b[i]){
				f_minus = false;
				break;
			}else if(a[i]>b[i]){
				break; 
			}
		}
	}
	if(f_minus){
		for(int i=0;i<=max(len1,len2)-1;i++){
			mminus[i] = mminus[i] + a[i] - b[i];
			if(mminus[i]<0){
				mminus[i] += 10;
				mminus[i+1]--;
			}
		}
	}else{
		for(int i=0;i<=max(len1,len2)-1;i++){
			mminus[i] = mminus[i] + b[i] - a[i];
			if(mminus[i]<0){
				mminus[i] += 10;
				mminus[i+1]--;
			}
		}
	}
	
	int cnt = max(len1,len2);
	for(int i=cnt-1;i>=0;i--){
		if(mminus[i] == 0){
			cnt--;
		}else{
			break;
		}
	}
	
	if(!cnt){
		printf("0");
	}else{
		if(!f_minus){
			printf("-");
		}
		for(int i=cnt-1;i>=0;i--){
			printf("%d",mminus[i]);
		}	
	}
	printf("\n");
}
void mutiply(int a[],int b[],int muti[]){
	int len1 = s1.size();
	int len2 = s2.size();
	for(int i=0;i<len1;i++){
		for(int j=0;j<len2;j++){
			muti[i+j] += a[i]*b[j];
		}
	}
	int jw = 0;
	for(int i=0;i<len1+len2-1;i++){
		muti[i] = muti[i] + jw;
		jw = muti[i]/10;
		muti[i] %= 10;
	}
	
	int cnt = 0;
	while(jw){
		muti[len1+len2+cnt-1] = jw%10;
		jw/=10;
		cnt++;
	}
	for(int i=len1+len2+cnt-2;i>=0;i--){
		printf("%d",muti[i]);
	}
	printf("\n");
}

int compare(int a[], int b[]) {
    if(a[0]>b[0]){
        return 1;
    }else if(a[0]<b[0]){
        return -1;
    }
    for (int i=a[0];i>0;i--){
        if (a[i]>b[i]){
            return 1;
        }else if(a[i]<b[i]){
            return -1;
        }
    }
    return 0;
}
void shift(int a[],int b[],int dis){
    for (int i=1;i<=a[0];i++){
        b[i+dis-1]=a[i];
    }
    b[0]=a[0]+dis-1;
}

void dividen(int a[],int b[],int divide[]){
	int len1 = s1.size();
	int len2 = s2.size();
    Ta[0] = len1;
    for(int i=0;i<len1;i++){
        Ta[len1-i] = s1[i]-'0';
    }
    Tb[0] = len2;
    for(int i=0;i<len2;i++){
        Tb[len2-i] = s2[i]-'0';
    }
    
    if(0==compare(Ta,Tb)){
        printf("1\n0\n");
    }else if (-1==compare(Ta,Tb)) {
        printf("0\n");
        cout << s1 << endl;
    }else {
    	int tmp[maxn];
        divide[0] = Ta[0]-Tb[0]+1;
        for(int i=divide[0];i>0;i--) {
            memset(tmp,0,sizeof(tmp));
            shift(Tb,tmp,i);
            while(compare(Ta,tmp)>=0) {
                divide[i]++;
                for(int j=1;j<=Ta[0];j++){
                    if(Ta[j]<tmp[j]) {
                        Ta[j+1]--;
                        Ta[j] += 10;
                    }
                    Ta[j] -= tmp[j];
                }
                int k = Ta[0];
                while(Ta[k]==0) {
                    k--;
                }
                Ta[0]=k;
            }
        }
        while (divide[0]>0 && divide[divide[0]]==0) {
            divide[0]--;
        }
	    for (int i=divide[0]; i>0; i--) {
	        printf("%d",divide[i]);
	    }
	    printf("\n");
	    if(0==Ta[0]) {
	    	printf("0\n");
	    }else{
	        for(int i=Ta[0];i>0;i--){
	            printf("%d",Ta[i]);
	        }
	        printf("\n");
	    }
    }
}

int main(){
	init();
	add(a,b,pplus);
	minu(a,b,mminus);
	mutiply(a,b,muti);
	dividen(a,b,divide);
	return 0;
}

模板006 分数类

这里给出分数类的模板(带约分函数)
模板不要求死记硬背,但要求根据算法的原理进行掌握,任何算法明确总体的思路一定是第一位的!

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

struct Fraction{					//分数类 
	int up;							//分子 
	int down;						//分母 
};

int gcd(int a,int b){				//求gcd最大公约数 
	if(b==0){
		return a;
	}else{
		return gcd(b,a%b);
	} 
}

Fraction reduction(Fraction f){		//约分 
	if(f.up == 0){
		f.down = 1;
	}
	
	if(f.down < 0 ){
		f.up = -f.up;
		f.down = -f.down;
	}
	
	int g = gcd(max(f.up,f.down),min(f.up,f.down));
	f.up /= g;
	f.down /=g;
	
	return f;
}

int main(){
	
	return 0;
}

模板007 全排列

这里给出全排列的模板
模板不要求死记硬背,但要求根据算法的原理进行掌握,任何算法明确总体的思路一定是第一位的!

#include<bits/stdc++.h>
using namespace std;
int N;
int a[15];
bool hashT[15];

void dfs(int depth){
	if(depth == N){
		for(int i=0;i<N;i++){
			cout << a[i];
		}
		printf("\n");
	}else{
		for(int i=1;i<=N;i++){
			if(!hashT[i]){
				hashT[i] = true;
				a[depth] = i;
				dfs(depth+1);
				hashT[i] = false;
			}
		}
	}
}

int main(){
	cin >> N;
	dfs(0);
	
	return 0;
}

模板008 全组合

这里给出全组合的模板
模板不要求死记硬背,但要求根据算法的原理进行掌握,任何算法明确总体的思路一定是第一位的!

#include<bits/stdc++.h>
using namespace std;
int N,R;
int a[25];
bool hashT[25];

void dfs(int depth,int index){
	if(depth == R){
		for(int i=0;i<R;i++){
			cout << a[i];
		}
		printf("\n");
	}else{
		for(int i=index;i<=N;i++){
			if(!hashT[i]){
				hashT[i] = true;
				a[depth] = i;
				dfs(depth+1,i+1);
				hashT[i] = false;
			}
		}
	}
}
 
int main(){
	scanf("%d%d",&N,&R);
	dfs(0,1);
	return 0;
}

--------------------------------------------------------------------------------

难度: 入门

P2524 Uim的情人节礼物·其之弐

算法标签: 数论 + 康托展开
注意点: 康托展开模板题,公式如下:
X=a[n] * (n-1)! +a[n-1]*(n-2)!+…+a[1] * 0!。

#include<bits/stdc++.h>
using namespace std;
char a[10];
int main(){
	int N;
	cin >> N;
	for(int i=0;i<N;i++){
		cin >> a[i];
	}
	int sum = 0;
	while(prev_permutation(a,a+N)){
		sum++;
	}
	sum++;
	cout << sum << endl;
	return 0;
} 

P1482 Cantor表(升级版)

算法标签: 数论 + 模拟
注意点: 约分gcd

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

int gcd (int a,int b){
	if(a<b){
		int tmp=a;
		a=b;
		b=tmp;
	}
	while(a%b){
		int tmp = a%b;
		a=b;
		b=tmp;
	}
	return b;
}
int main(){
	int a1,a2,b1,b2;
	scanf("%d/%d",&a1,&b1);
	scanf("%d/%d",&a2,&b2);
	int a =(a1)*(a2);
	int b =(b1)*(b2);
	int tmp = gcd(a,b);
	a=a/tmp;
	b=b/tmp;
	cout << b << " " << a <<endl;
	return 0;
}

P1146 硬币翻转

算法标签: 数论 + 模拟

#include<bits/stdc++.h>
using namespace std;
int a[101];
int main(){
	int N;
	cin >> N;
	cout << N << endl;
	int j = 1;
	for(int i=0;i<N;i++){
		int tmp = N-1;
		int p=(j+i)%N;
		while(tmp){
			a[p] = a[p] ^ 1;
			p = (p+1)%N;
			tmp--;
		}
		for(int k=0;k<N;k++){
			cout << a[k];
		}
		cout << endl;
	}
	return 0;
} 

P1615 西游记公司

算法标签: 数论 + 模拟

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

int main(){
	string x,y;
	cin >> x >> y;
	int k;
	cin >> k;
	int a[3]={0},b[3]={0};
	int p=0;
	for(int i=0;i<x.length();){
		if(x[i]!=':'){
			a[p] = a[p]*10 +(x[i]-'0');
			i++;
		}else{
			i++;
			p++;
		}
	}
	p=0;
	for(int i=0;i<y.length();){
		if(y[i]!=':'){
			b[p] = b[p]*10 +(y[i]-'0');
			i++;
		}else{
			i++;
			p++;
		}
	}
	for(int i=2;i>=0;i--){
		if(b[i]<a[i]){
			b[i-1]--;
			b[i]+=60;
		}
		b[i]-=a[i];
	}
		
	long long  result = b[0]*3600 +b[1]*60 +b[2];
	result = result*k;
	cout << result <<endl;
	return 0;
}

P1200 [USACO1.1]你的飞碟在这儿Your Ride Is Here

算法标签: 数论 + 字符串

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

int main(){
	char str1[8],str2[8];
	cin >> str1 >> str2;
	int mutiply=1;
	for(int i=0;i<strlen(str1);i++){
		mutiply = mutiply *(str1[i]-'A'+1);
	}
	int num1 = mutiply % 47;
	mutiply = 1;
	for(int i=0;i<strlen(str2);i++){
		mutiply = mutiply *(str2[i]-'A'+1);
	}
	int num2 =mutiply % 47;
	if(num1==num2){
		cout << "GO"<<endl;
	}else{
		cout <<"STAY"<<endl;
	}
	return 0;
}

P1554 梦中的统计

算法标签: 数论 + 模拟

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

int main(){
	int M,N; 
	int a[11];
	memset(a,0,sizeof(a));
	cin >> M >> N;
	for(int i=M;i<=N;i++){
		int k=i;
		while(k>0){
			a[k%10]++;
			k/=10;
		}
	}
	for(int i=0;i<10;i++){
		cout << a[i] << " ";
	}
	cout << endl;
	return 0;
}

P2043 质因子分解

算法标签: 数论 + 素数

#include<bits/stdc++.h>
using namespace std;
int a[10001]={1,1,0};
int c[1500];
int p[1500];
int main(){
	int N;
	cin >>N;
	memset(p,0,sizeof(p));
	for(int i=2;i<=10000;i++){
		for(int j=2*i;j<=10000;j=j+i){
			if(!a[j]){
				a[j]=1;
			}
		}
	}
	int j=0;
	for(int i=0;i<=10000;i++){
		if(a[i]==0){
			c[j]=i;
			j++;
		}
	}
	
	for(int k=2;k<=N;k++){
		int tmp=k;
		for(int i=0;i<j && tmp>1;){
			if(tmp%c[i]==0){
				tmp/=c[i];
				p[i]++;
			}else{
				i++;
			}
		}
	}
	
	for(int i=0;i<j;i++){
		if(p[i]){
			cout << c[i] <<" "<<p[i]<<endl;
		}
	}

	return 0;
}

P2669 [NOIP2015 普及组] 金币

算法标签: 数论 + 高斯公式1+2+…+n

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

int main(){
	int sum =0;
	int K;
	cin >> K;
	int n=1;
	while(n*(n+1)/2<K){
		n++ ;
	}
	n--;
	for(int i=1;i<=n;i++){
		sum = sum + i * i;
	}
	K -=(n*(n+1))/2;
	while(K>0){
		sum += (n+1);
		K--;
	}
	cout << sum <<endl;
	return 0;
} 

P5534 【XR-3】等差数列

算法标签: 数论 + 等差数列公式

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

int main(){
	long long sum;
	long long a1,a2,n;
	cin >> a1>>a2>>n;
	long long d=a2-a1;
	sum = a1*n +(n-1)*n/2*d;
	cout << sum << endl;
	return 0;
} 

P1720 月落乌啼算钱(斐波那契数列)

算法标签: 数论 + Fibonacci

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

int main(){
	double a[50]={0,1,1};
	int N;
	cin >> N;
	for(int i=3;i<=48;i++){
		a[i] = a[i-1]+a[i-2];
	}
	printf("%.2lf",a[N]);
	return 0;
}

P1035 [NOIP2002 普及组] 级数求和

算法标签: 数论 + 模拟

#include<bits/stdc++.h>

using namespace std;

int main(){
	int k;
	cin >> k;
	int n=1;
	double sum=0.0;
	do{
		sum=sum+1.0/n;
		n++;
	}while(k>=sum);
	cout << n-1;
	return 0;
}

P1304 哥德巴赫猜想

算法标签: 数论 + 素数

#include<bits/stdc++.h>
using namespace std;
bool t[10001]={1,1,0};
int main(){
	int N;
	cin >>N;
	for(int i=2;i<=N;i++){
		for(int j=2*i;j<=N;j+=i){
			if(t[i]){
				continue;
			}else{
				t[j]=1;
			}
		}
	}
	for(int i=4;i<=N;i=i+2){
		for(int j=2;j<N-1;j++){
			if(!t[j] && !t[i-j]){
				cout << i << "=" << j <<"+"<< i-j<<endl;
				break;
			}
		}
	}
}

P1150 Peter的烟

算法标签: 数论 + 模拟

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

int main(){
	int n,k;
	cin >> n >> k;
	int oral = n;
	int count = 0;
	while(n/k){
		count = count + n/k;
		n = n - n/k*k +n/k;
	}
	cout << oral+count << endl;
	return 0;
} 

P1876 开灯

算法标签: 数论
注意点: 公式结论题,完全平方数

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

int main(){
	long long N;
	cin >> N;
	for(long long i=1;i*i<=N;i++){
		cout << i*i << " ";
	}
	cout <<endl;
	return 0;
}

P1888 三角函数

算法标签: 数论 + 排序

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

int main(){
	int a[3];
	for(int i=0;i<3;i++){
		cin >> a[i];
	} 
	sort(a,a+3);
	int b=a[0];
	int c=a[2];
	while(c%b){
		int tmp =c % b;
		c = b;
		b = tmp; 
	}
	a[0]/=b;
	a[2]/=b;
	cout << a[0] <<"/"<< a[2] <<endl; 
	return 0;
}

P4413 [COCI2006-2007#2] R2

算法标签: 数论 + 方程

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

int main(){
	int R1,S;
	cin >> R1 >>S;
	cout << 2*S-R1<<endl;
	return 0;
}

P1590 失踪的7

算法标签: 数论

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

int main(){
	int t;
	cin >>t;
	for(int i=0;i<t;i++){
		long long n;
		cin >> n;
		long long sum =1;
		long long result =0;
		for(;n;){
			int tmp = n % 10;
			if(tmp>=7){
				tmp--;
			}
			result = result + sum * tmp;
			sum *=9;
			n=n/10;
		}
		cout << result << endl;
		
	}
	return 0;
}

P1075 [NOIP2012 普及组] 质因数分解

算法标签: 数论

#include<bits/stdc++.h>
using namespace std;
int main(){
	int n,p1,p2;
	cin >> n;
	for(int i=2;i<=sqrt(n);i++){
		if(n%i==0){
			p1=i;
			p2=n/i;
			break;
		}
	}
	if(p1>=p2){
		cout <<p1;
	}else{
		cout <<p2;
	}
	return 0; 
} 

P1851 好朋友

算法标签: 数论 + 枚举

#include<bits/stdc++.h>
using namespace std;
int a[]={220,1184,2620,5020,6232,10744,12285,17296,63020};
int b[]={284,1210,2924,5564,6368,10856,14595,18416,76084};
int main(){
	int s;
	cin >> s;
	for(int i=0;i<9;i++){
		if(a[i]>=s){
			cout << a[i] << " "<<b[i]<<endl;
			return 0;
		}
		if(b[i]>=s){
			cout << b[i] << " "<< a[i]<< endl;
			return 0;
		}
	}
	
	return 0;
}

P1634 禽兽的传染病

算法标签: 数论

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

int main(){
	long long x,n,result=1;
	cin >> x >> n;
	for(int i=0;i<n;i++){
		result*=(1+x);
	}
	cout << result;
	return 0;
} 

P1652 圆

算法标签: 计算几何

#include<bits/stdc++.h>
using namespace std;
int x[51];
int y[51];
int r[51];

int dis(int x1,int y1,int x2,int y2,int r){
	double distance = sqrt((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2));
	if(distance<=r){
		return 1;
	}else{
		return 0;
	}
}
int main(){
	int n;
	cin >> n;
	for(int i=0;i<n;i++){
		cin >> x[i];
	}
	for(int i=0;i<n;i++){
		cin >> y[i];
	}
	for(int i=0;i<n;i++){
		cin >> r[i];
	}
	int sum = 0;
	int x1,y1,x2,y2;
	cin >> x1 >> y1 >> x2 >> y2;
	for(int i=0;i<n;i++){
		if((!dis(x1,y1,x[i],y[i],r[i])&&dis(x2,y2,x[i],y[i],r[i]))||
		(dis(x1,y1,x[i],y[i],r[i])&&!dis(x2,y2,x[i],y[i],r[i]))){
			sum ++;
		}
	}
	cout << sum << endl;
	return 0;
} 

P1887 乘积最大3

算法标签: 数论

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

int main(){
	long long N,M;
	cin >> N >> M;
	long long ave = N/M;
	int tmp= N%M;
	for(int i=0;i<M-tmp;i++){
		cout << ave << " ";
	}
	for(int i=0;i<tmp;i++){
		cout << ave+1 << " ";
	}
	cout <<endl;
	return 0;
}

P2525 Uim的情人节礼物·其之壱

算法标签: 数论 + 排列

#include<bits/stdc++.h>
using namespace std;
int a[10];
int b[10];
int main(){
	int N;
	cin >> N;
	for(int i=0;i<N;i++){
		cin >> a[i];
	}
	if(prev_permutation(a,a+N)){
		for(int i=0;i<N;i++){
			cout << a[i] <<" ";
		}	
		cout <<endl;
	}else{
		cout << "ERROR" << endl;
	}
	return 0;
} 

P2415 集合求和

算法标签: 数论

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

int main(){
	int i=0;
	int a[1000];
	memset(a,0,sizeof(a));
	char ch[1000];
	gets(ch);	
	int tmp=0;
	int j=0;
	for(int i=0;i<strlen(ch);i++){
		if(ch[i]>='0' && ch[i]<='9'){
			tmp = tmp*10 + (ch[i] -'0');
		}else{
			a[j]=tmp;
			j++;
			tmp=0;
		}
	}
	if(tmp!=0){
		a[j]=tmp;
		j++;
	}
	long long sum =0;
	for(int i=0;i<j;i++){
		sum += a[i];
	} 
	
	double coff = pow(2,j-1);
	long long co =int(coff);
	sum = sum * co;
	cout << sum << endl;
	
	return 0;
}

P2705 小球

算法标签: 数论

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

int main(){
	int R,B,C,D,E;
	cin >> R >> B;
	cin >> C >> D >> E;
	int k;
	if(R>=B){
		k=1;
	}else{
		k=0;
	}
	int sum = 0;
	if(C+D>=2*E){
		sum = R*C+B*D;
		cout << sum <<endl ;
	}else{
		if(k==1){
			sum = B*2*E +(R-B)*C;
			cout << sum <<endl;
		}else{
			sum = R*2*E +(B-R)*D;
			cout << sum <<endl;
		}
	}
	
	return 0;
} 

P1425 小鱼的游泳时间

算法标签: 数论 + 模拟

#include<stdio.h>
#include<stdlib.h> 
#include<iostream>
using namespace std;
int main(){
	int a=0,b=0,c=0,d=0,e=0,f=0;
	scanf("%d%d%d%d",&a,&b,&c,&d);
	e=c-a;
	f=d-b;
	if(f<0){
		e--;
		f+=60;
	}
	printf("%d %d",e,f);
	return 0;
}

P7257 [COCI2009-2010#3] FILIP

算法标签: 数论 + 模拟

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

int main(){
	int a,b;
	cin >> a >> b;
	int a1 = 0,b1 = 0;
	while(a){
		a1 = a1*10 + (a%10);
		a/=10;
	}
	while(b){
		b1 = b1*10 + (b%10);
		b/=10;
	}
	cout << max(a1,b1);
	
	return 0;
} 

P7573 「PMOI-3」公平の意

算法标签: 数论 + 模拟
注意点: 一个蛋糕不用切,因此n=1时,要特判0的输出,其余情况输出 ⌈ n 2 ⌉ \lceil \frac{n}{2} \rceil 2n

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

int main(){
	int t;
	cin >> t;
	while(t--){
		int n;
		cin >> n;
		if(n == 1){
			cout << "0" << endl;
		}else{
			int ans = ceil(n*1.0/2);
			cout << ans << endl;
		}
	}
	
	return 0;
} 

P6421 [COCI2008-2009#2] RESETO

算法标签: 数论 + 素数筛
注意点: 埃拉托色尼筛法模板题

#include<bits/stdc++.h>
using namespace std;
const int maxn = 1e3+5;
int n,k;
int a[maxn] = {1,1,0};

int main(){
	cin >> n >> k;
	for(int i=2;i<=n;i++){
		if(!a[i]){
			k--;
			if(k==0){
				cout << i << endl;
				return 0;
			}
			for(int j=2*i;j<=n;j+=i){
				if(!a[j]){
					a[j] = 1;
					k--;	
				}
				if(k==0){
					cout << j << endl;
					return 0;
				}
			}
		}
	}
	
	return 0;
}

P7933 [COCI2007-2008#5] PASCAL

算法标签: 数论 + 素数
注意点: 特判n=1!

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

int main(){
	int n;
	cin >> n;
	if(n==1){
		cout << "0" << endl;
	}else{
		int u = -1;
		for(int i=2;i<=sqrt(n);i++){
			if(n%i==0){
				u = i;
				break;
			}
		}
		if(u == -1){
			cout << n-1 << endl;
		}else{
			cout << n - n/u << endl;
		}
	}
	return 0;
}

P7199 [COCI2019-2020#1] Trol

算法标签: 数论
注意点: 这是一道好题!一个数N各位反复相加的总和为(N-1)%9+1,每10个数字一轮循环,因此枚举最后的(不足10个)数字即可

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

int main(){
	int Q;
	long long l,r;
	cin.tie(0);
	cout.tie(0);
	cin >> Q;
	for(int i=0;i<Q;i++){
		cin >> l >> r;
		long long k = (r-l)/9;
		long long sum = 0;
		sum += 45*k;
		for(long long i=l+9*k;i<=r;i++){
			sum += (i-1) % 9 + 1;
		}
		printf("%lld\n",sum);
	}
	return 0;
}

P7892 『JROI-3』R.I.P.

算法标签: 数论
注意点: 求一个数分解成两个最大的公因数

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

int main(){
	int T;
	cin >> T;
	while(T--){
		int n,m;
		cin >> n >> m;
		int u = -1;
		for(int i=sqrt(n);i>=2;i--){
			if(n%i==0){
				u = i;
				break;
			}
		}
		int need;
		if(u == -1){
			need = (2+(n+1)) * 2;
		}else{
			need = ((u+1) + (n/u+1))*2;
		}
		if(need <= m){
			printf("Good\n");
		}else{
			printf("Miss\n");
		}
	}
	
	return 0;
}

P7772 [COCI 2009-2010 #2] FAKTOR

算法标签: 数论

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

int main(){
	int A,I;
	cin >> A >> I;
	cout << (I-1)*A + 1 << endl; 
	
	return 0;
}

P7441 「EZEC-7」Erinnerung

算法标签: 数论
注意点: x=0,y=0要分4种情况讨论并特判!

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

int main(){
	int T;
	cin >> T;
	while(T--){
		LL x,y,k;
		cin >> x >> y >> k;
		LL t = max(x,y);
		if(t == 0){
			cout << "0" << endl;
		}else if(x==0 && y){
			if(k%y == 0){
				cout << "1" << endl;
			}else{
				cout << "0" << endl;
			}
		}else if(x && y==0){
			if(k%x == 0){
				cout << "1" << endl; 
			}else{
				cout << "0" << endl;
			}
		}else{
			cout << k/t << endl;
		}
	}	
	
	return 0;
}

P7226 [COCI2015-2016#3] POT

算法标签: 数论 + 模拟

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

int main(){
	int n;
	int ans = 0;
	cin >> n;
	while(n--){
		int p;
		cin >> p;
		int e = p%10;
		p/=10;
		int t = 1;
		while(e--){
			t *= p;
		}
		ans += t;
	}
	cout << ans << endl;
	return 0;
}

P7909 [CSP-J 2021] 分糖果

算法标签: 数论 + 模拟
注意点: 取余数的最大值即可

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

int main(){
	int n,L,R;
	cin >> n >> L >> R; 
	if(R-L>=n){
		cout << n-1 << endl;
	}else{
		int p1 = L%n;
		int p2 = R%n;
		if(p1<=p2){
			cout << p2 << endl;
		}else{
			cout << n-1 << endl;
		}
	}
	return 0;
}

--------------------------------------------------------------------------------

难度: 普及-

P1579 哥德巴赫猜想(升级版)

算法标签: 数论 + 素数
注意点: 三层循环,按序枚举,有结果即字典序最小输出

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

int main(){
	int a[20000]={1,1,0};
	int result[5000];
	int N;
	cin >> N;
	for(int i=2;i<20000;i++){
		if(a[i]){
			continue;
		}
		for(int j=i*i;j<20000;j+=i){
			a[j]=1;
		}
	}
	int j=0;
	for(int i=2;i<=N;i++){
		if(!a[i]){
			result[j]=i;	
			j++;
		}
	}
	for(int i=0;i<j;i++){
		for(int p=0;p<j;p++){
			for(int q=0;q<j;q++)
			if(result[i]+result[p]+result[q]==N){
				cout << result[i] << " " << result[p] << " " << result[q] <<endl;
				return 0;
			} 
		}
	}
	
	return 0;
}

P2026 求一次函数解析式

算法标签: 计算几何
注意点: 分数约分

#include<bits/stdc++.h>
using namespace std;
struct Fraction{
	int up;
	int down;
};

Fraction reduction(Fraction f){
	if(f.down<0){
		f.up = -f.up;
		f.down = -f.down;
	}
	if(f.up == 0){
		f.down = 1; 
	}
	int g = __gcd(abs(max(f.up,f.down)),abs(min(f.up,f.down)));
	f.up /= g;
	f.down /= g;
	return f;
}
int main(){
	int x1,y1,x2,y2;
	cin >> x1 >> y1 >> x2 >> y2;
	Fraction k;
	k.up = (y2-y1);
	k.down = (x2-x1);
	k = reduction(k);
	
	Fraction b;
	b.up = y1*k.down - k.up*x1;
	b.down = k.down;
	b = reduction(b);
	
	cout << "y=";
	if(k.down == 1){
		if(k.up!=0){
			printf("%dx",k.up);
		}
	}else{
		printf("%d/%d*x",k.up,k.down);
	}
	
	if(b.down == 1){
		if(b.up!=0){
			printf("%+d\n",b.up);
		}
	}else{
		printf("%+d/%d\n",b.up,b.down);
	}
	
	return 0;
}

P1755 斐波那契的拆分

算法标签: Fibonacci
注意点: 从后向前枚举Fibonacci数,存储在栈中,然后逆序输出
若采用dfs搜索,则会发生超时(TLE)

#include<bits/stdc++.h>
using namespace std;
const int maxn = 1e9+5;
int f[105] = {1,1};
int cnt;
int n;
stack<int> s;

void init(){
	for(int i=2;;i++){
		f[i] = f[i-1] + f[i-2];
		if(f[i] > maxn){
			cnt = i;
			break;
		}
	}
}

int main(){
	int t;
	cin >> t;
	init();
	
	while(t--){
		cin >> n;
		int n1 = n;
		for(int i=cnt;i>=0 && n;i--){
			if(f[i]>n){
				continue;
			}else{
				n -= f[i];
				s.push(f[i]);
			}
		}
		printf("%d=",n1);
		int t = 0;
		while(!s.empty()){
			if(t == 0){
				printf("%d",s.top());
			}else{
				printf("+%d",s.top());
			}
			t++;
			s.pop();
		}
		printf("\n");
	}
	
	return 0;
} 

P2368 EXCEEDED WARNING B

算法标签: 数论 + 平方数
注意点: 一道好题!这道题考察了对于平方数的理解
当n<=8时,无解
当n=9时 有8个满足要求的数:
111111111
119357639
380642361
388888889
611111111
619357639
880642361
888888889
容易知道,某个数的平方为987654321时,以这个数结尾的数,它的平方也是987654321
所以当n>9时,满足条件的数只能以上述八个数结尾
当n=10时,由于最高位不为0,所以有8*9=72个
n=11时,720个;n=12时,7200个…以此类推

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

int main(){
	int n;
	cin >> n;
	if(n<=8){
		cout << "0";
	}else{
		if(n == 9){
			cout << "8";
		}else{
			cout << "72";
			for(int i=10;i<n;i++){
				cout << "0";
			}
		}
	}
	
	return 0;
} 

P2067 Cytus-Holyknight

算法标签: 计算几何
注意点: 这道题的易错点非常多:
1.可能包含以下几种解析表达式:y=kx+b,y=b,x=b,当线竖直的时候,需要特判斜率
2.题目存在着许多坐标不完整的情况,比如:
样例1:
3
010
111
x1x
样例4:
3
0x0
1x1
010
样例10:
15
000001000000000
000001000000000
000001000000000
000001000000000
000001000000000
000001000000000
000001000000000
x1111111111111x
000001000000000
000001000000000
000001000000000
000001000000000
000001000000000
000001000000000
000001000000000
需要在这种情况下识别坐标
3.注意0.0000在k or b上的输出!

#include<bits/stdc++.h>
using namespace std;
char s[20][20];

int main(){
	int n;
	cin >> n;
	for(int i=1;i<=n;i++){
		scanf("%s",s[i]+1);
	}
	int row,column;
	bool flag1 = true;
	bool flag2 = true;
	for(int i=1;i<=n;i++){
		for(int j=1;j<=n;j++){
			if(s[i][j] == '1'){
				bool f1 = true;
				bool f2 = true;
				for(int k=1;k<=n;k++){
					if(s[k][j] == '1' || s[k][j] == 'x'){
						continue;
					}else{
						f1 = false;
						break;
					}
				}
				if(f1){
					column = j;
					flag1 = false;
				}
				for(int k=1;k<=n;k++){
					if(s[i][k] == '1' || s[i][k] == 'x'){
						continue;
					}else{
						f2 = false;
						break;
					}
				}
				if(f2){
					row = i;
					flag2 = false;
				}
			}	
			if(!flag1 && !flag2){
				break;
			}
		}
		if(!flag1 && !flag2){
			break;
		}
	}
	int cnt = 2;
	int x1,y1,x2,y2;
	for(int i=1;i<=n && cnt;i++){
		for(int j=1;j<=n && cnt;j++){
			if(s[i][j] == 'x'){
				if(cnt>1){
					x1 = j-column;
					y1 = row-i;
				}else{
					x2 = j-column;
					y2 = row-i;
				}
				cnt--;
			} 
		}
	}
	double k,b;
	if(x1==x2){
		printf("x=%.4lf",x1*1.0);
		return 0;
	}else{
		k = (1.0*(y2-y1))/(1.0*(x2-x1));
		b = (y1-k*x1);
	}
	
	printf("y=");
	if(fabs(k)<1e-4){
		if(fabs(b)<1e-4){
			printf("0.0000\n");
		}else{
			printf("%.4lf\n",b);
		}	
	}else{
		printf("%.4lfx",k); 
		if(fabs(b)<1e-4){
			
		}else{
			printf("%+.4lf\n",b);
		}	
	}
	
	return 0;
} 

P1497 木牛流马

算法标签: 排列组合
注意点: 可重复元素的排列数目需除去重复的元素自排列个数

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

int main(){
	int n,k,h;
	cin >> n >> k >> h;
	LL ans = 1;
	for(int i=1;i<=k;i++){
		ans *= (n-i+1)*(n-i+1);
	}
	for(int i=1;i<=h;i++){
		int t;
		scanf("%d",&t);
		for(int j=1;j<=t;j++){
			ans /= j;
		}
	}
	printf("%lld\n",ans);
	return 0;
} 

P1143 进制转换

算法标签: 数论 + 进制

#include<bits/stdc++.h>
using namespace std;
int a[105];
int ans = 0;
int main(){
	int n;
	cin >> n;
	char s[105];
	scanf("%s",s);
	int m;
	cin >> m;
	int id = 0;
	for(int i=0;i<strlen(s);i++){
		if(n>10 && s[i]>='A'){
			id = id*n + s[i] - 'A' + 10;
		}else{
			id = id*n + s[i] - '0';
		}
	}
	while(id){
		int t = id % m;
		a[ans++] = t;
		id /= m;
	}
	for(int i=ans-1;i>=0;i--){
		if(a[i]>=10){
			printf("%c",a[i]-10+'A');
		}else{
			printf("%c",a[i]+'0');
		}
	} 
	printf("\n");
	return 0;
}

P1372 又是毕业季I

算法标签: 数论 + gcd
注意点: 默契度最大的元素就是取最大公约数最小的数, min ⁡ ( g c d ) \min(gcd) min(gcd)

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


int main(){
	int n,k;
	cin >> n >> k;
	cout << n/k <<endl;
	return 0;
}

P1458 [USACO2.1]顺序的分数 Ordered Fractions

算法标签: 数论 + 排序
注意点: 注意数组的空间要大于16000,注意排序判等时误差设置尽可能小[测试点3]

#include<bits/stdc++.h>
using namespace std;
struct Fraction{
	int up;
	int down;
	double res;
};
Fraction f[20005];
int cnt = 0;
int gcd(int a,int b){
	if(b == 0){
		return a;
	}else{
		return gcd(b,a%b);
	}
}
Fraction reduction(Fraction f){
	if(f.up == 0){
		f.down = 1;
	}
	if(f.down < 0){
		f.up = -f.up;
		f.down = -f.down;
	}
	int g = gcd(f.down,f.up);
	f.up /= g;
	f.down /= g;
	return f;
} 
bool cmp(Fraction f1,Fraction f2){
	return f1.res < f2.res;
}
int main(){
	int n;
	cin >> n;
	for(int i=0;i<=n;i++){
		for(int j=i;j<=n;j++){
			f[cnt].up = i;
			f[cnt].down = j;
			f[cnt] = reduction(f[cnt]);
			f[cnt].res = (1.0*f[cnt].up)/(1.0*f[cnt].down);
			cnt++;
		}
	}	
	sort(f,f+cnt,cmp);
	for(int i=0;i<cnt;i++){
		if(fabs(f[i+1].res-f[i].res)<1e-6){
			continue;
		}else{
			printf("%d/%d\n",f[i].up,f[i].down);
		}
	}
	return 0;
} 

P1024 [NOIP2001 提高组] 一元三次方程求解

算法标签: 方程 + 分治
注意点: 依次枚举-100 - +100之间的每个区间[x,x+1),检查方程的根是否落在这个区间内部,此外,注意特殊情形——端点处取得

#include<bits/stdc++.h>
using namespace std;
const double eps = 1e-4;
double a,b,c,d;
int count1 = 0;
double p[5];

double f(double x,double a,double b,double c,double d){
	double ans = a*x*x*x + b*x*x + c*x + d;
	return ans;
}
void part(double left,double right,double a,double b,double c,double d){
	if(fabs(f(left,a,b,c,d))<eps){
		p[count1++] = left;
		return;
	}
	if(fabs(right-left)<eps){
		p[count1++] = left;
		return;
	}
	double mid = (left+right)/2.0;
	if(f(left,a,b,c,d)*f(mid,a,b,c,d)<=0){
		return part(left,mid,a,b,c,d);
	}
	if(f(mid,a,b,c,d)*f(right,a,b,c,d)<=0){
		return part(mid,right,a,b,c,d);
	}
}
int main(){
	cin >> a >> b >> c >> d;
	double left,right;
	for(int i=-100;i<=100;i++){
		left = i*1.0;
		right = left + 1.0 - eps;
		part(left,right,a,b,c,d);
	}
	
	for(int i=0;i<3;i++){
		printf("%.2lf ",p[i]);
	}
	return 0;
}

P1029 [NOIP2001 普及组] 最大公约数和最小公倍数问题

算法标签: 数论 + gcd/lcm
注意点: 由于两个数的乘积最大不超过xy,因此依次枚举1-sqrt(x*y)内所有的数,逐一进行判断!

#include<bits/stdc++.h>
using namespace std;
int gcd(int a,int b){
	int a1 = max(a,b);
	int b1 = min(a,b);
	while(a1%b1){
		int tmp=b1;
		b1=a1%b1;	
		a1=tmp;
	}
	return b1;
}
int main(){
	int x,y;
	cin >> x >> y;
	if(y==0 || x==0 ||y%x!=0){
		cout << "0" <<endl;
		return 0;
	}else if(y/x==1){
		cout << "1" <<endl;
		return 0;
	}
	
	int ans=0;
	for(int i=1;i<=sqrt(1ll*x*y);i++){
		if(1ll*x*y%i==0 && gcd((1ll*x*y)/i,i)==x){
			ans++;
		}
	}
	ans = ans * 2;
	cout << ans << endl;
	return 0;
}

P1044 [NOIP2003 普及组] 栈

算法标签: 数论 + Catalan数
注意点: 卡特兰数模板题

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

int main(){
	int n;
	long long ans = 1;
	cin >>n;
	for(int i=1;i<=n;i++){
		ans = ans * (n+i)/i;
	}
	ans = ans /(n+1);
	
	cout << ans << endl;
}

P1595 信封问题

算法标签: 数论 + 动态规划
注意点: 递推式:D(n) = (n-1) * [D(n-1) + D(n-2)]

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
LL a[25]={0,0,1,2};
 
int main(){
	int n;
	cin >> n;
	for(int i=4;i<=n;i++){
		a[i] = (i-1)*(a[i-1]+a[i-2]);
	}
	printf("%lld\n",a[n]);
	return 0;
} 

P1591 阶乘数码

算法标签: 数论 + 高精
注意点: 高精度*低精度,按数组逆序计算

#include<bits/stdc++.h>
using namespace std;
int a[3005];

int main(){
	int t;
	cin >> t;
	
	while(t--){
		int n;
		int a1;
		cin >> n >> a1;
		memset(a,0,sizeof(a));
		a[0] = 1;
		int cnt = 1;
		for(int i=1;i<=n;i++){
			int jw = 0;
			for(int j=0;j<cnt;j++){
				a[j]*=i;
			}
			for(int j=0;j<cnt;j++){
				a[j] += jw;
				jw = a[j]/10;
				a[j] %= 10;
			}
			while(jw){
				a[cnt] = jw%10;
				cnt++;
				jw/=10;
			}
		}
		int ans = 0;
		for(int i=0;i<cnt;i++){
			if(a[i] == a1){
				ans++;
			}
		}
		cout << ans << endl; 
	}
	
	return 0;
} 

P2241 统计方形(数据加强版)

算法标签: 数论
注意点: 找规律

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

int main(){
	int a,b;
	cin >> a >> b;
	long long zcount = 0;
	long long ccount =0;
	int minsize = min(a,b);
	int maxsize = max(a,b);
	for(int i=1;i<=minsize;i++){
		zcount = zcount + (a-i+1)*(b-i+1);
	}
	cout << zcount << " ";
	for(int i=1;i<=b;i++){
		for(int j=i+1;j>i && j<=a;j++){
			ccount = ccount +(b-i+1)*(a-j+1);
		}
	}
	for(int j=1;j<=a;j++){
		for(int i=j+1;i>j && i<=b;i++){
			ccount = ccount + (b-i+1)*(a-j+1);
		}
	}
	cout << ccount <<endl;
	return 0;
}

P7127 「RdOI R1」一次函数(function)

算法标签: 计算几何
注意点: 先解两条直线的交点(-1,-1),然后求面积和S,通过裂项相消的方法得到最终的表达式为 Γ ( n ) = n 2 ∗ ( n + 1 ) , ∀ n ∈ N \Gamma(n) = \frac{n}{2*(n+1)},\quad\forall n\in\mathbb N Γ(n)=2(n+1)n,nN,最后输出时注意gcd约分

#include<bits/stdc++.h>
using namespace std;
int gcd(int a,int b){
	if(b==0){
		return a;
	}else{
		return gcd(b,a%b);
	}
}

int main(){
	int t;
	cin >> t;
	while(t--){
		int n;
		cin >> n;
		if(n<1){
			printf("0\n");
		}else{
			int up = n;
			int down = 2*(n+1);
			int g = gcd(down,up);
			up /= g;
			down /= g;
			printf("%d/%d\n",up,down);
		}
	}
	
	return 0;
} 

P7354 「PMOI-1」骑士の棋

算法标签: 数论
注意点: 找规律,分别讨论以下几种情况:
1.骑士在角上
2.骑士在边上
3.骑士在内部
我们假设国王可以移动的范围为X个,那么所需骑士的数量为 ⌈ X 2 ⌉ \lceil \frac{X}{2} \rceil 2X

#include<bits/stdc++.h>
using namespace std;
int xx[] = {1,1,1,0,0,-1,-1,-1};
int yy[] = {1,0,-1,1,-1,1,0,-1};

int main(){
	int t;
	cin >> t;
	while(t--){
		int cnt = 0;
		int n,m,x,y;
		cin >> n >> m >> x >> y;
		for(int i=0;i<8;i++){
			int tx = xx[i] + x;
			int ty = yy[i] + y;
			if(tx>=1 && tx<=n && ty>=1 && ty<=m){
				cnt++;
			}
		}
		int ans = ceil(1.0*cnt/2.0);
		cout << ans << endl;
	}
	
	return 0;
} 

P1088 [NOIP2004 普及组] 火星人

算法标签: 数论 + 康托展开

#include<bits/stdc++.h>
using namespace std;
int a[10005];

int main(){
	int N;
	scanf("%d",&N);
	int k;
	cin >> k;
	for(int i=0;i<N;i++){
		scanf("%d",&a[i]);
	}
	while(k--){
		next_permutation(a,a+N);
	}
	for(int i=0;i<N;i++){
		printf("%d ",a[i]);
	}
	printf("\n");
	return 0;
}

P1100 高低位交换

算法标签: 数论 + 位运算

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

int main(){
	int n;
	cin >> n;
	int di = 0xffff;
	int gao = 0xffff0000;
	unsigned int t1 = (n&di) << 16;
	unsigned int t2 = (n&gao) >> 16;
	unsigned int ans = t1+t2;
	cout << ans << endl;
	return 0;
} 

P1832 A+B Problem(再升级)

算法标签: 素数 + 背包dp
注意点: 完全背包问题

#include<bits/stdc++.h>
using namespace std;
int a[1005]={1,1,0};
long long dp[1005];
void shai(int n){
	for(int i=2;i<=n;i++){
		for(int j=2;i*j<=n;j++){
			if(!a[i*j]){
				a[i*j]=1;
			}
		}
	}
}
int main(){
	int n;
	cin >> n;
	shai(n);
	memset(dp,0,sizeof(dp));
	
	dp[0] = 1;
	for(int i=2;i<=n;i++){
		if(!a[i]){
			for(int j=i;j<=n;j++){
				dp[j] += dp[j-i];
			}
		}
	}
	cout << dp[n] << endl;
	return 0;
} 

P1009 [NOIP1998 普及组] 阶乘之和

算法标签: 数论 + 高精
注意点: 每一轮迭代都需要进行高精加+高精乘运算

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


int main(){
	int N;
	int mul[1000]={1},sum[1000]={0};
	cin >> N;
	for(int k=1;k<=N;k++){
		int jw = 0;
		for(int i=0;i<1000;i++){
			mul[i] = mul[i] * k + jw ;
			jw = mul[i] / 10;
			mul[i] = mul[i] % 10;
		}
		jw= 0 ;
		for(int i=0;i<1000;i++){
			
			sum[i] = sum[i] + mul[i] + jw ;
			jw = sum[i] / 10;
			sum[i] = sum[i] % 10;
		}
	}
	int flag=0;
	for(int i=999;i>=0;i--){
		if(sum[i]==0){
			
		}else{
			flag = 1;
		}
		if(flag){
			cout << sum[i];
		}
	}
	cout << endl;
	return 0;
}

P1010 [NOIP1998 普及组] 幂次方

算法标签: 数论 + DFS
注意点: 一道好题!这道题既考察了对数论进制转换的理解,又考察了对DFS的应用,由于答案输出是带有嵌套模式的,因此DFS较为合理,此外,一个数分解成2的幂,等价于将其转换成二进制数,两者结合即可输出结果

#include<bits/stdc++.h>
using namespace std;
string dfs(int n){
	int i = 0;
	string s = "";
	if(n==0){
		return string("0");
	}
	do{
		if(n&1){
			s =(i==1? "2":"2(" + dfs(i) + ")") + (s==""? "":"+") + s;
		}
	}while(i++,n>>=1); 
	return s;
}

int main(){
	
	int n;
	cin >> n;
	cout << dfs(n) << endl;
	
	return 0;
}

P1062 [NOIP2006 普及组] 数列

算法标签: 数论 + 进制
注意点: k进制转换

#include<bits/stdc++.h>
using namespace std;
long long a[12];
int main(){
	memset(a,0,sizeof(a));
	int k,N;
	cin >> k >> N;
	long long tmp = 1;
	for(int i=0;i<11;i++){
		a[i]=tmp;
		tmp*=k;
	}
	long long ans = 0;
	int oct=0;
	while(N>0){
		if(N%2==1){
			ans += a[oct];
		}
		N/=2;
		oct++;
	}
	cout <<ans << endl;
	return 0;
}

P1226 【模板】快速幂||取余运算

算法标签: 数论 + 快速幂
注意点: 快速幂模板

#include<bits/stdc++.h>
using namespace std;
long long b,p,k;

int main(){
	cin >> b >> p >> k;
	long long b1 = b,p1 = p,k1 = k;
	long long ans = 1;
	if(k == 1){
		printf("%lld^%lld mod %lld=%lld\n",b1,p1,k1,0);
		return 0;
	}
	while(p){
		if(p&1){
			ans = (ans*b) % k;
		}
		b = (b*b)%k;
		p >>= 1;
	}
	printf("%lld^%lld mod %lld=%lld\n",b1,p1,k1,ans);
	return 0;
} 

P1589 泥泞路

算法标签: 数论 + 贪心
注意点: 泥泞路的尾端不计算在覆盖内

#include<bits/stdc++.h>
using namespace std;
struct node{
	int s;
	int t;
};
node mud[10005];
bool cmp(node m1,node m2){
	if(m1.s!=m2.s){
		return m1.s < m2.s;
	}else{
		return m1.t < m2.t;
	}
}
int main(){
	int n,L;
	scanf("%d%d",&n,&L);
	for(int i=0;i<n;i++){
		scanf("%d%d",&mud[i].s,&mud[i].t);
	} 
	sort(mud,mud+n,cmp);
	int start = 0;
	int cnt = 0;
	for(int i=0;i<n;i++){
		if(start<=mud[i].s){
			int len = min(mud[n-1].t-1,mud[i].t) - mud[i].s;
			int T = (ceil)((len*1.0)/(L*1.0));
			cnt += T;	
			start = mud[i].s + T*L;
		}else if(start<=mud[i].t){
			int len = min(mud[n-1].t-1,mud[i].t) - start;
			int T = (ceil)((len*1.0)/(L*1.0));
			cnt += T;
			start += T*L;
		}
	}
	cout << cnt << endl;
	return 0;
} 

P2556 [AHOI2002]黑白图像压缩

算法标签: 数论 + 位运算
注意点: 位运算操作结果保留一位数0或1

#include<bits/stdc++.h>
using namespace std;
int a[10005];
int ans[80005];

int main(){
	int n;
	cin >> n;
	for(int i=0;i<n/8;i++){
		cin >> a[i];
	}
	for(int i=0;i<n/8;i++){
		int t = 128;
		for(int j=0;j<8;j++){
			ans[i*8+j] = (t&a[i])>>(8-j-1);
			t >>= 1;
		}
	}
	int start = ans[0]; 
	int cnt = 1;
	for(int i=1;i<n;i++){
		if(start == ans[i]){
			cnt++;
		}else{
			int res = 0;
			if(start == 1){
				res += (1<<7);
			}
			res |= cnt;
			printf("%d ",res);
			cnt = 1;
			start = ans[i];
		}
	}
	if(cnt){
		int res = 0;
		if(start == 1){
			res += (1<<7);
		}
		res |= cnt;
		printf("%d ",res);
	}
	return 0;
} 

P2429 制杖题

算法标签: 数论 + 素数筛
注意点: 素数筛的变式

#include<bits/stdc++.h>
using namespace std;
map<int,int> mp;
const int P = 376544743;
int ans = 0;
int main(){
	int n,m;
	cin >> n >> m;
	for(int i=1;i<=n;i++){
		int t;
		cin >> t;
		for(int j=t;j<=m;j+=t){
			if(!mp[j]){
				mp[j] = 1;
				ans += j;
				ans %= P;
			}
		}
	}	
	cout << ans << endl;
	return 0;
} 

P3913 车的攻击

算法标签: 数论
注意点: map会超时,用unordered_map+O2优化

#include<bits/stdc++.h>
using namespace std;
unordered_map<int,int> mp1;
int rcnt = 0;
unordered_map<int,int> mp2;
int ccnt = 0;
int main(){
	int N,K;
	cin >> N >> K;
	for(int i=0;i<K;i++){
		int r,c;
		scanf("%d%d",&r,&c);
		if(!mp1[r]){
			mp1[r] = 1;
			rcnt++;
		}
		if(!mp2[c]){
			mp2[c] = 1;
			ccnt++;
		}
	}
	long long ans = 1LL*(rcnt+ccnt)*N - 1LL*rcnt*ccnt;
	printf("%lld\n",ans);
	
	return 0;
} 

P6039 「ACOI2020」音速

算法标签: 计算几何
注意点: 题意描述不是很清楚,可略过此题

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

int main(){
	double x,y,r;
	cin >> x >> y >> r;
	x = fabs(x);
	y = fabs(y);
	double ans = 2*r - sqrt(x*x+y*y);
	ans = fabs(ans);
	printf("%.6lf\n",ans);
	if(x!=0 && y==0){
		printf("Error\n");
	}else{
		if(x==0){
			printf("0.00\n");
		}else{
			if(x/y!=0){
				printf("%.2lf\n",x/y); 
			}else{
				printf("0.00\n");
			} 
		}
	}
	
	return 0;
} 

P1170 兔八哥与猎人

算法标签: 数论 + gcd
注意点: 两点之间的连线不经过任何点,要求 Γ : g c d ( ∣ x 1 − x 2 ∣ , ∣ y 1 − y 2 ∣ ) = 1 \Gamma:gcd(|x1-x2|,|y1-y2|)=1 Γ:gcd(x1x2,y1y2)=1

#include<bits/stdc++.h>
using namespace std;
int gcd(int a,int b){
	if(b>a){
		swap(a,b);
	}
	if(b==0){
		return a;
	}else{
		return gcd(b,a%b);
	}
}
int main(){
	int ax,ay,bx,by;
	int n;
	cin >> n;
	while(n--){
		cin >> ax >> ay >> bx >> by;
		int g = gcd(abs(ax-bx),abs(ay-by));
		if(g==1){
			printf("no\n");
		}else{
			printf("yes\n");
		}
	}
	
	
	return 0;
} 

P1202 [USACO1.1]黑色星期五Friday the Thirteenth

算法标签: 数论
注意点: 闰年2月有29天

#include<bits/stdc++.h>
using namespace std;
int a[15]={0,31,28,31,30,31,30,31,31,30,31,30,31};
int ans[10];

int islunar(int y){
	if((y%4==0 && y%100!=0) || y%400==0){
		return 1;
	}else{
		return 0;
	}
}
int main(){
	int n;
	cin >> n;
	int start = 1900;
	int t = 13;
	for(int i=0;i<n;i++){
		int nowy = start + i;
		if(islunar(nowy)){
			a[2] = 29; 
		}else{
			a[2] = 28;
		}
		for(int j=1;j<=12;j++){
			ans[t%7]++;
			t += a[j];
		}
	} 
	printf("%d",ans[6]);
	for(int i=0;i<6;i++){
		printf(" %d",ans[i]);
	}
	printf("\n");
	return 0;
} 

P1211 [USACO1.3]牛式 Prime Cryptarithm

算法标签: 数论 + 枚举
注意点: 依次枚举乘数与被乘数,然后检验竖式计算的结果是否符合预期

#include<bits/stdc++.h>
using namespace std;
int a[15];
set<int> s;
int main(){
	int n;
	cin >> n;
	for(int i=0;i<n;i++){
		cin >> a[i];
		s.insert(a[i]);
	}
	sort(a,a+n);
	int cnt = 0;
	if(a[0] == 0){
		for(int i=1;i<n;i++){
			int ans1 = 0;
			ans1 += a[i];
			ans1 *= 10;
			for(int j=0;j<n;j++){
				ans1 += a[j];
				ans1 *= 10;
				for(int k=0;k<n;k++){
					ans1 += a[k];
					int ans2 = 0;
					for(int p=1;p<n;p++){
						ans2 += a[p];
						ans2 *= 10;
						for(int q=0;q<n;q++){
							ans2 += a[q];
							int t1 = ans1*a[q];
							int t2 = ans1*a[p];
							int t = ans1*ans2;
							if(t1>=100 && t1<=999 && t2>=100 && t2<=999 && t>=1000 && t<=9999){
								bool f = true;
								while(f && t1){
									if(s.find(t1%10)==s.end()){
										f = false;
									}
									t1/=10;
								}
								while(f && t2){
									if(s.find(t2%10)==s.end()){
										f = false;
									}
									t2/=10;
								}
								while(f && t){
									if(s.find(t%10)==s.end()){
										f = false;
									}
									t/=10;
								}
								if(f){
									cnt++;
								}
							}
							ans2 -= a[q];
						}
						ans2 /= 10;
						ans2 -=a[p];
					}
					ans1 -= a[k];
				}
				ans1 /= 10;
				ans1 -= a[j];
			}
			ans1 /= 10;
			ans1 -= a[i];
		}
	}else{
		for(int i=0;i<n;i++){
			int ans1 = 0;
			ans1 += a[i];
			ans1 *= 10;
			for(int j=0;j<n;j++){
				ans1 += a[j];
				ans1 *= 10;
				for(int k=0;k<n;k++){
					ans1 += a[k];
					int ans2 = 0;
					for(int p=0;p<n;p++){
						ans2 += a[p];
						ans2 *= 10;
						for(int q=0;q<n;q++){
							ans2 += a[q];
							int t1 = ans1*a[q];
							int t2 = ans1*a[p];
							int t = ans1*ans2;
							if(t1>=100 && t1<=999 && t2>=100 && t2<=999 && t>=1000 && t<=9999){
								bool f = true;
								while(f && t1){
									if(s.find(t1%10)==s.end()){
										f = false;
									}
									t1/=10;
								}
								while(f && t2){
									if(s.find(t2%10)==s.end()){
										f = false;
									}
									t2/=10;
								}
								while(f && t){
									if(s.find(t%10)==s.end()){
										f = false;
									}
									t/=10;
								}
								if(f){
									cnt++;
								}
							}
							ans2 -= a[q];
						}
						ans2 /= 10;
						ans2 -=a[p];
					}
					ans1 -= a[k];
				}
				ans1 /= 10;
				ans1 -= a[j];
			}
			ans1 /= 10;
			ans1 -= a[i];
		}
	}
	cout << cnt << endl;
	return 0;
} 

P1258 小车问题

算法标签: 数论 + 方程
注意点: 小学奥数题,列方程 Θ f : ( s − 2 x ) + ( s − x ) b = x a \Theta f:\frac{(s-2x)+(s-x)}{b} = \frac{x}{a} Θf:b(s2x)+(sx)=ax,解得 x = 2 a s 3 a + b x=\frac{2as}{3a+b} x=3a+b2as,得到总时间为 t = x a + s − x b t=\frac{x}{a}+\frac{s-x}{b} t=ax+bsx

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

int main(){
	int s,a,b;
	cin >> s >> a >> b;
	double x = (2*a*s*1.0)/(3*a+b);
	double ans = x/a + (s-x)/b;
	printf("%.6lf\n",ans);
	
	return 0;
}

P1293 班级聚会

算法标签: 数论 + 枚举

#include<bits/stdc++.h>
using namespace std;
struct node{
	int num;
	int dis;
	string city;
};
node n[155];
int main(){
	int cnt = 0;
	int Edis = INT_MAX;
	int u = -1;
	while(1){
		cin >> n[cnt].num >> n[cnt].dis >> n[cnt].city;
		cnt++;
		if(n[cnt-1].city == "Moscow"){
			break;
		}
	}
	for(int i=0;i<cnt;i++){
		int ans = 0;
		for(int j=0;j<cnt;j++){
			if(j!=i){
				ans += n[j].num * (abs(n[j].dis-n[i].dis));
			}
		}
		if(ans < Edis){
			Edis = ans;
			u = i;
		}else if(ans == Edis){
			if(n[u].dis>n[i].dis){
				u = i;
			}
		}
	}
	cout << n[u].city << " ";
	printf("%d\n",Edis);
	return 0;
}

P1093 [NOIP2007 普及组] 奖学金

算法标签: 数论 + 排序

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

typedef struct award{
	int No;
	int score1;
	int score2;
	int score3;
	int total;
}student;
student stu[301]; 
bool cmp(student stu1,student stu2){
	if(stu1.total<stu2.total){
		return false;
	}else if(stu1.total==stu2.total){
		if(stu1.score1>stu2.score1){
			return true;
		}else if(stu1.score1==stu2.score1){
			if(stu1.No<stu2.No){
				return true;
			}else{
				return false;
			}
		}else{
			return false;
		}
	}else{
		return true;
	}
}
int main(){
	int N;
	cin >> N;
	int a,b,c;
	for(int i=0;i<N;i++){
		cin >> a >> b >> c;
		stu[i].No=i+1;
		stu[i].score1=a;
		stu[i].score2=b;
		stu[i].score3=c;
		stu[i].total=a+b+c;
	}
	sort(stu,stu+N,cmp);
	for(int i=0;i<5;i++){
		cout << stu[i].No << " " <<stu[i].total << endl; 
	} 
	
	return 0;
}

P3383 【模板】线性筛素数

算法标签: 数论 + 素数筛
注意点: 素数筛+快读模板题,复杂度   O ( n l o g n ) \ O(nlogn)  O(nlogn)

#include<bits/stdc++.h>
using namespace std;
const int maxn = 1e7;
int p[maxn+5];
bool vis[maxn*10+5];
int cnt = 0;
int n,q;
inline int read(){
    int f = 1, val = 0; char ch = getchar();
    while ((ch < '0' || ch > '9') && (ch != '-')) ch = getchar();
    if (ch == '-') f = -1, ch = getchar();
    while (ch >= '0' && ch <= '9') val = (val << 3) + (val << 1) + ch - '0', ch = getchar();
    return val * f;
}
 
void prime(int n){
	for(register int i=2;i<=n;i++){
		if(!vis[i]){
			p[cnt++] = i;
		}
		for(register int j=0;j<cnt && i*p[j]<=n;j++){
			vis[i*p[j]] = 1;
			if(i%p[j]==0){
				break;
			}
		}
	}
}
int main(){
	n = read();
	vis[1] = 1;
	prime(n);
	q = read();
	for(register int i=0;i<q;i++){
		int k;
		k = read();
		printf("%d\n",p[k-1]);
	}
	return 0;
} 

P3152 正整数序列

算法标签: 数论 + 分治
注意点: 我们可以将序列一分为二,每次变换较大的序列,使之成为较小序列的一部分,这样只需要   l o g 2 ( n ) + 1 \ log2(n)+1  log2(n)+1次变换即可

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

int main(){
	int n;
	cin >> n;
	int ans = (floor)(log2(n))+1;
	cout << ans << endl;
	return 0;
}

P4057 [Code+#1]晨跑

算法标签: 数论 + lcm
注意点: 最小公倍数模板题

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

ll gcd(ll a,ll b){
	return b==0 ? a : gcd(b,a%b) ;
}
ll lcm(ll a,ll b){
	if(a<b){
		swap(a,b);
	}
	ll tmp = gcd(a,b);

	return 1LL*(a)*(b/tmp);
} 

int main(){
	ll a,b,c;
	cin >> a >> b >> c;
	ll ans = lcm(a,b);
	ans = lcm(ans,c);
	cout << ans << endl;
	return 0;
}

P5990 [PA2015]Kieszonkowe

算法标签: 数论
注意点: 无解的情况只能是当偶数一个都没有,而奇数恰好有一个的时候,此时无论如何整数和都不可能是偶数

#include<bits/stdc++.h>
using namespace std;
const int maxn = 1e6+5;
int odd[maxn];
int even[maxn];
int cnt1 = 0;
int cnt2 = 0;

int main(){
	int n;
	cin >> n;
	for(int i=0;i<n;i++){
		int t;
		cin >> t;
		if(t%2){
			odd[cnt1++] = t;
		}else{
			even[cnt2++] = t;
		}
	}	
	sort(odd,odd+cnt1);
	if(cnt2==0 && cnt1==1){
		cout << "NIESTETY" << endl;
		return 0;
	}
	int ans = 0;
	for(int i=0;i<cnt2;i++){
		ans += even[i];
	}
	if(cnt1%2){
		for(int i=cnt1-1;i>=1;i--){
			ans += odd[i];
		}
	}else{
		for(int i=cnt1-1;i>=0;i--){
			ans += odd[i];
		}
	}
	cout << ans << endl;
	return 0;
}

P6546 [COCI2010-2011#2] PUŽ

算法标签: 数论

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

int main(){
	int a,b,v;
	cin >> a >> b >> v;
	int ans = (ceil)((v-a)*1.0/(a-b));
	ans += 1;
	cout << ans << endl;
	return 0;
}

P6188 [NOI Online #1 入门组] 文具订购

算法标签: 数论
注意点: 依次枚举0-13所有可能的情况,逐一判断最佳的购买方案数!

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

int main(){
	int n;
	cin >> n;
	int a=0,b=0,c=0;
	if(n==0){
		cout << "0 0 0" << endl;
		return 0;
	}else if(n<=2 || n==5){
		cout << "-1" << endl;
		return 0;
	}
	int ans = n/14;
	int now = n%14;
	a = b = c = ans;
	if(now == 1){
		a--;
		b--;
		c+=4;
	}else if(now == 2){
		a--;
		c+=3;
	}else if(now == 3){
		c++;
	}else if(now == 4){
		b++;
	}else if(now == 5){
		a--;
		c+=4;
	}else if(now == 6){
		c+=2;
	}else if(now == 7){
		b+=1;
		c+=1;
	}else if(now == 8){
		b+=2;
	}else if(now == 9){
		c+=3;
	}else if(now == 10){
		b+=1;
		c+=2;
	}else if(now == 11){
		b+=2;
		c+=1;
	}else if(now == 12){
		c+=4;
	}else if(now == 13){
		b+=1;
		c+=3;
	}
	cout << a << " " << b << " " << c << endl; 

	return 0;
}

P6746 『MdOI R3』Operations

算法标签: 数论
注意点: 一道好题!分4种情况进行讨论:
1.a=0 且 b=0,此时的代价为0
2.a=0 或 b=0,此时的代价为d,即   0 ∗ A = 0 , A A + 1 = 0 \ 0*A=0,\frac{A}{A+1}=0  0A=0,A+1A=0
3.a=b时,代价为c或者2*d的最小值,原因是 A A + 1 = 0 , B B + 1 = 0 , \frac{A}{A+1}=0,\frac{B}{B+1}=0, A+1A=0,B+1B=0,两次操作等价于一次操作
4.   a ! = b \ a!=b  a!=b的时候,取   c + d \ c+d  c+d   2 ∗ d \ 2*d  2d的较小值

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

int main(){
	LL a,b,c,d;
	cin >> a >> b >> c >> d;
	if(a==0 && b==0){
		cout << "0" << endl;
	}else if(a==0 || b==0){
		cout << d << endl;
	}else if(a==b){
		cout << min(c,2*d) << endl;
	}else{
		cout << min(c+d,2*d) << endl;
	}
	
	return 0;
}

P5514 [MtOI2019]永夜的报应

算法标签: 数论
注意点: 一道好题!事实上无需分组,直接求异或和即为最小!
  a ⊕ b < = a + b \ a \oplus b<=a+b  ab<=a+b

#include<bits/stdc++.h>
using namespace std;
const int maxn = 1e6+5;
int a[maxn];
int main(){
	int n;
	cin >> n;
	for(int i=0;i<n;i++){
		scanf("%d",&a[i]);
	}
	int ans = 0;
	for(int i=0;i<n;i++){
		ans ^= a[i];
	}
	cout << ans << endl;
	return 0;
}

P5657 [CSP-S2019] 格雷码

算法标签: 数论 + DFS
注意点: 一道好题!格雷码+DFS,需注意:
1.“倒序”指的是n-1位格雷码在序列中的位置{从后向前数),而不是指n-1位格雷码倒过来拼接上“0”或“1”
2.不要使用pow函数,因为精度不够,自定义一个函数power
3.注意数据范围最大为64位,需用unsigned long long

#include<bits/stdc++.h>
using namespace std;
typedef unsigned long long LL;
LL power(LL n){
	LL ans = 1;
	for(LL i=1;i<=n;i++){
		ans *= 2;
	}
	return ans;
}
string dfs(LL n,LL k){
	if(n==1){
		if(k==0){
			return string("0");
		}else if(k==1){
			return string("1");
		}
	}
	
	if(k>=power(n-1)){
		string s = dfs(n-1,power(n)-k-1);
		return "1" + s; 
	}else{
		return "0" + dfs(n-1,k);
	}
}

int main(){
	LL n,k;
	cin >> n >> k;
	string s = dfs(n,k);
	cout << s << endl;
	return 0;
}

P1287 盒子与球

算法标签: 数论
注意点: Stirling数模板题

#include<bits/stdc++.h>
using namespace std;
int stirling(int n,int m){
	if(n<m || m<=0){
		return 0;
	}else if(n == m){
		return 1;
	}else{
		return m*stirling(n-1,m) + stirling(n-1,m-1);
	}
} 

int main(){
	int n,r;
	cin >> n >> r;
	int ans = stirling(n,r);
	for(int i=1;i<=r;i++){
		ans *= i;
	}
	cout << ans << endl;
	return 0;
}

P1932 A+B A-B A*B A/B A%B Problem

算法标签: 数论 + 高精
注意点: 一道高精算法的经典题!本题是高精度算法的大集合,包含了高精加、高精减、高精乘、高精除、高精模除,需仔细掌握高精算法的原理,并注意实现的细节!

#include<bits/stdc++.h>
using namespace std;
const int maxn = 2e4+5;
int a[maxn];
int b[maxn];
int pplus[maxn];
int mminus[maxn];
int muti[maxn];
int Ta[maxn];
int Tb[maxn];
int divide[maxn];
string s1,s2;

void init(){
	cin >> s1 >> s2;
	int len1 = s1.size();
	int len2 = s2.size();
	for(int i=0;i<len1;i++){
		a[len1-i-1] = s1[i] - '0';
	}	
	for(int i=0;i<len2;i++){
		b[len2-i-1] = s2[i] - '0';
	}
} 

void add(int a[],int b[],int pplus[]){
	int jw = 0;
	int len1 = s1.size();
	int len2 = s2.size();
	for(int i=0;i<max(len1,len2);i++){
		pplus[i] = a[i] + b[i] + jw;
		jw = pplus[i] / 10;
		pplus[i] %= 10;
	}
	
	if(jw){
		pplus[max(len1,len2)] = jw;
		for(int i=max(len1,len2);i>=0;i--){
			printf("%d",pplus[i]);
		}
		printf("\n");
	}else{
		for(int i=max(len1,len2)-1;i>=0;i--){
			printf("%d",pplus[i]);
		}
		printf("\n");
	}
}
void minu(int a[],int b[],int mminus[]){
	bool f_minus = true;
	int len1 = s1.size();
	int len2 = s2.size();
	if(len2>len1){
		f_minus = false;
	}else if(len2 == len1){
		for(int i=len2-1;i>=0;i--){
			if(a[i]<b[i]){
				f_minus = false;
				break;
			}else if(a[i]>b[i]){
				break; 
			}
		}
	}
	if(f_minus){
		for(int i=0;i<=max(len1,len2)-1;i++){
			mminus[i] = mminus[i] + a[i] - b[i];
			if(mminus[i]<0){
				mminus[i] += 10;
				mminus[i+1]--;
			}
		}
	}else{
		for(int i=0;i<=max(len1,len2)-1;i++){
			mminus[i] = mminus[i] + b[i] - a[i];
			if(mminus[i]<0){
				mminus[i] += 10;
				mminus[i+1]--;
			}
		}
	}
	
	int cnt = max(len1,len2);
	for(int i=cnt-1;i>=0;i--){
		if(mminus[i] == 0){
			cnt--;
		}else{
			break;
		}
	}
	
	if(!cnt){
		printf("0");
	}else{
		if(!f_minus){
			printf("-");
		}
		for(int i=cnt-1;i>=0;i--){
			printf("%d",mminus[i]);
		}	
	}
	printf("\n");
}
void mutiply(int a[],int b[],int muti[]){
	int len1 = s1.size();
	int len2 = s2.size();
	for(int i=0;i<len1;i++){
		for(int j=0;j<len2;j++){
			muti[i+j] += a[i]*b[j];
		}
	}
	int jw = 0;
	for(int i=0;i<len1+len2-1;i++){
		muti[i] = muti[i] + jw;
		jw = muti[i]/10;
		muti[i] %= 10;
	}
	
	int cnt = 0;
	while(jw){
		muti[len1+len2+cnt-1] = jw%10;
		jw/=10;
		cnt++;
	}
	for(int i=len1+len2+cnt-2;i>=0;i--){
		printf("%d",muti[i]);
	}
	printf("\n");
}

int compare(int a[], int b[]) {
    if(a[0]>b[0]){
        return 1;
    }else if(a[0]<b[0]){
        return -1;
    }
    for (int i=a[0];i>0;i--){
        if (a[i]>b[i]){
            return 1;
        }else if(a[i]<b[i]){
            return -1;
        }
    }
    return 0;
}
void shift(int a[],int b[],int dis){
    for (int i=1;i<=a[0];i++){
        b[i+dis-1]=a[i];
    }
    b[0]=a[0]+dis-1;
}

void dividen(int a[],int b[],int divide[]){
	int len1 = s1.size();
	int len2 = s2.size();
    Ta[0] = len1;
    for(int i=0;i<len1;i++){
        Ta[len1-i] = s1[i]-'0';
    }
    Tb[0] = len2;
    for(int i=0;i<len2;i++){
        Tb[len2-i] = s2[i]-'0';
    }
    
    if(0==compare(Ta,Tb)){
        printf("1\n0\n");
    }else if (-1==compare(Ta,Tb)) {
        printf("0\n");
        cout << s1 << endl;
    }else {
    	int tmp[maxn];
        divide[0] = Ta[0]-Tb[0]+1;
        for(int i=divide[0];i>0;i--) {
            memset(tmp,0,sizeof(tmp));
            shift(Tb,tmp,i);
            while(compare(Ta,tmp)>=0) {
                divide[i]++;
                for(int j=1;j<=Ta[0];j++){
                    if(Ta[j]<tmp[j]) {
                        Ta[j+1]--;
                        Ta[j] += 10;
                    }
                    Ta[j] -= tmp[j];
                }
                int k = Ta[0];
                while(Ta[k]==0) {
                    k--;
                }
                Ta[0]=k;
            }
        }
        while (divide[0]>0 && divide[divide[0]]==0) {
            divide[0]--;
        }
	    for (int i=divide[0]; i>0; i--) {
	        printf("%d",divide[i]);
	    }
	    printf("\n");
	    if(0==Ta[0]) {
	    	printf("0\n");
	    }else{
	        for(int i=Ta[0];i>0;i--){
	            printf("%d",Ta[i]);
	        }
	        printf("\n");
	    }
    }
}

int main(){
	init();
	add(a,b,pplus);
	minu(a,b,mminus);
	mutiply(a,b,muti);
	dividen(a,b,divide);
	return 0;
}

P1327 数列排序

算法标签: 数论 + 排序
注意点: 和PAT甲级 1067题类似,不同点在于,本题的数列值可以是负数,且交换时不一定和0交换(交换空间任意)
因此我们需要map来记录原数组的下标,交换数组时map里面的值也需要交换(更新)

#include<bits/stdc++.h>
using namespace std;
const int maxn = 1e5+5;
int a[maxn];
int b[maxn];
map<int,int> mp;
int main(){
	int N;
	scanf("%d",&N);
	
	for(int i=0;i<N;i++){
		scanf("%d",&a[i]);
		mp[a[i]] = i;
		b[i] = a[i];
	}
	sort(b,b+N);
	int cnt = 0;
	for(int i=0;i<N;i++){
		if(a[i]!=b[i]){
			int t = mp[b[i]];
			mp[a[i]] = t;
			mp[b[i]] = i;
			swap(a[t],a[i]);
			cnt++;
		}
	}
	cout << cnt << endl;
	return 0;
} 

P5436 【XR-2】缘分

算法标签: 数论
注意点: 拥有最大最小公倍数的数字,一定是相邻的两项!(PAT 乙级 P1104与之类似)

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

LL gcd(LL a,LL b){
	if(b==0){
		return a;
	}else{
		return gcd(b,a%b);
	}
}

int main(){
	int T;
	cin >> T;
	while(T--){
		LL n;
		cin >> n;
		if(n==1){
			cout << "1" << endl;	
		}else{
			LL ans = 1;
			for(LL i=n;i>=1;i--){
				if(gcd(i,i-1)==1){
					ans = i*(i-1);
					break;
				} 
			}
			cout << ans << endl;
		}
	}
	
	return 0;
}

P1358 扑克牌

算法标签: 数论 + 排列组合
注意点: 组合数问题

#include<bits/stdc++.h>
using namespace std;
const int P = 10007;
int dp[10005][105] ={0};
int a[105];
int main(){
	int n,m;
	cin >> n >> m;
	
	dp[1][0] = 1;
	dp[1][1] = 1;
	for(int i=2;i<=n;i++){
		for(int j=0;j<=min(i,100);j++){
			if(j==0 || j==i){
				dp[i][j] = 1;
			}else{
				dp[i][j] = (dp[i-1][j] + dp[i-1][j-1]) % P;
			}
		}
	}	
	for(int i=1;i<=m;i++){
		cin >> a[i];
	}
	int ans = 1;
	for(int i=1;i<=m;i++){
		ans *= dp[n][a[i]];
		ans %= P;
		n -= a[i];
	}
	cout << ans << endl;
	return 0;
} 

P3984 高兴的津津

算法标签: 数论

#include<bits/stdc++.h>
using namespace std;
const int maxn = 2e5+5;
typedef long long LL;
int a[maxn];

LL cnt = 0;
int main(){
	int n;
	LL T;
	cin >> n >> T;
	for(int i=0;i<n;i++){
		cin >> a[i];
	}
	LL s = a[0];
	for(int i=0;i<n;i++){
		if(s>a[i]){
			cnt += (a[i] + T - s);
			s = a[i] + T;
		}else{
			cnt += T;
			s = a[i] + T;
		}
	} 
	cout << cnt << endl;
	return 0;
}

P1067 [NOIP2009 普及组] 多项式输出

算法标签: 数论 + 模拟

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

int main(){
	int a[102];
	int N;
	cin >> N;
	int p = N;
	for(int i=0;i<=N;i++){
		cin >> a[i];
	}
	int i=0;
	int flag=0;
	
	for(int i=0;i<=N;i++){
		while(!a[i] && !flag){
			i++;
			p--;
		}
		if(p==1){
			if(!flag){
				
			}else{
				if(a[i]>0){
					cout << "+" ; 
				}
			}
			if(a[i]>1){
				cout << a[i] << "x";
			}
			if(a[i]==1){
				cout << "x";
			}	
			if(a[i]==-1){
				cout << "-x";
			}
			if(a[i]<-1){
				cout << a[i] << "x";
			}
		}else if(p>1){
			if(!flag){
				
			}else{
				if(a[i]>0){
					cout << "+" ; 
				}
			}
			if(a[i]>1){
				cout << a[i] << "x^" << p;
			}
			if(a[i]==1){
				cout << "x^" << p;
			}	
			if(a[i]==-1){
				cout << "-x^" << p;
			}
			if(a[i]<-1){
				cout << a[i] << "x^" << p;
			}
		}else if(p==0){
			if(!flag){
				
			}else{
				if(a[i]>0){
					cout << "+" << a[i]; 
				}else if(a[i]<0){
					cout << a[i];
				}
			}
		} 
		flag = 1;
		p--;
	}
	
	return 0;
} 

P1147 连续自然数和

算法标签: 数论
注意点: 高斯求和

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

int main(){
	int M;
	scanf("%d",&M);
	for(int k1 =sqrt(2*M);k1>1;k1--){
		if(2*M % k1 == 0){
			int k2 = 2*M / k1;
			if((k1+k2)%2==1){
				printf("%d %d\n",(k2-k1+1)/2,(k1+k2-1)/2);
			}
		}
	}
	return 0;
}

P1866 编号

算法标签: 数论 + 排序
注意点: 组合取数问题

#include<bits/stdc++.h>
using namespace std;
const long long mod = 1000000007;
long long ans = 1;

int b[100];

int main(){
	int N;
	scanf("%d",&N);
	for(int i=0;i<N;i++){
		scanf("%d",&b[i]);
	}
	
	sort(b,b+N);
	
	for(int i=0;i<N;i++){
		ans = (ans*(b[i]-i)) % mod;
	}
	
	printf("%lld\n",ans);
	return 0;
}

P2640 神秘磁石

算法标签: 数论 + 素数筛

#include<bits/stdc++.h>
using namespace std;
const int maxn = 1e4+5;
bool a[maxn] = {1,1,0};
void init(){
	for(int i=2;i<maxn;i++){
		if(!a[i]){
			for(int j=2*i;j<maxn;j+=i){
				a[j] = 1;
			} 
		}
	}
}

int main(){
	init();
	int n,k;
	cin >> n >> k;
	int cnt = 0;
	for(int i=2;i<=n-k;i++){
		if(!a[i] && !a[i+k]){
			printf("%d %d\n",i,i+k);
			cnt++;
		}
	}
	if(!cnt){
		printf("empty\n"); 
	}
	return 0;
} 

P4122 [USACO17DEC]Blocked Billboard B

算法标签: 数论 + 模拟
注意点: 一道好题,以下给出的是   O ( 1 ) \ O(1)  O(1)的算法

#include<bits/stdc++.h>
using namespace std;
int a[5];
int b[5][3];
int main(){
	int x1,y1,x2,y2;
	int x3,y3,x4,y4;
	int x5,y5,x6,y6;
	cin >> x1 >> y1 >> x2 >> y2 
	>> x3 >> y3 >> x4 >> y4 
	>> x5 >> y5 >> x6 >> y6;
	int ans = abs(x1-x2)*abs(y1-y2) + abs(x3-x4)*abs(y3-y4);
	int t1 = max(0,min(x2,x6)-max(x1,x5))*max(0,min(y2,y6)-max(y1,y5));
	int t2 = max(0,min(x4,x6)-max(x3,x5))*max(0,min(y4,y6)-max(y3,y5));
	ans -= t1;
	ans -= t2;
	cout << ans << endl;
	return 0;
} 

P1011 [NOIP1998 提高组] 车站

算法标签: 数论 + Fibonacci数列

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

int a[21];
void fibo(int a[]){
	a[1]=1;
	a[2]=1;
	for(int i=3;i<=20;i++){
		a[i]=a[i-1]+a[i-2];
	}
}

int main(){
	int a1,n,m,x1;
	cin >> a1 >> n >> m >> x1;
	fibo(a);
	if(n==1||n==2||n==3){
		cout << a << endl;
		return 0;
	}
	if(x1==n){
		cout <<"0"<<endl;
	}
	int tmpa = 2; 
	for(int i=1;i<=n-5;i++){
		tmpa = tmpa +a[i];
	}
	
	int tmpx = 0;
	for(int i=1;i<=n-4;i++){
		tmpx = tmpx +a[i];
	}
	m = m -tmpa*a1;
	int x;
	x = m / tmpx;
	tmpa = 2;
	for(int i=1;i<=x1-4;i++){
		tmpa =tmpa+a[i];
	}
	tmpx=0;
	for(int i=1;i<=x1-3;i++){
		tmpx = tmpx +a[i];
	}
	int ans = a1*tmpa +x*tmpx;
	cout << ans << endl;
	return 0;
} 

P1218 [USACO1.5]特殊的质数肋骨 Superprime Rib

算法标签: 数论 + DFS
注意点: 每层DFS相当于多了一个数位

#include<bits/stdc++.h>
using namespace std;
int ans[10005];
int n;

int isprime(int n){
	if(n<2){
		return 0;
	}
	for(int i=2;i<=sqrt(n);i++){
		if(n % i==0){
			return 0;
		}
	}
	return 1;
}
int cnt = 0;
void dfs(int depth,int num){
	if(depth == n){
		if(isprime(num)){
			ans[cnt++] = num;
		}
		return;
	}
	for(int i=1;i<=9;i++){
		if(isprime(num*10+i)){
			dfs(depth+1,num*10+i);
		}
	}
}
int main(){
	cin >> n;
	dfs(0,0);
	sort(ans,ans+cnt);
	for(int i=0;i<cnt;i++){
		printf("%d\n",ans[i]);
	}

	return 0;
} 

P1102 A-B 数对

算法标签: 数论 + 模拟

#include<bits/stdc++.h>
using namespace std;
const int maxn = 2e5+5;
int a[maxn];

int main(){
	int N,C;
	long long ans = 0;
	scanf("%d%d",&N,&C);
	for(int i=0;i<N;i++){
		scanf("%d",&a[i]);
	}
	sort(a,a+N);
	int i = 0,j = 0;
	long long count = 1;
	while(i<=j && j<=N){
		if(a[j]-a[i]>C){
			i++;
		}else if(a[j]-a[i] == C){
			if(a[j] == a[j+1]){
				count++;
				j++;
			}else{
				if(a[i] == a[i+1]){
					ans += count;
					i++;
				}else{
					ans += count;
					i++;
					count =1;
				}
			}
		}else{
			j++;
		}
	}
	printf("%lld\n",ans);
	return 0;
} 

P1326 足球

算法标签: 数论
注意点:
一道好题!这道题反复提交了十多次才通过,认真总结了一下本题的思路:
我们分别对最大得分和最小得分进行讨论——
最大得分:
1.当进球数   S > = N − 1 \ S>=N-1  S>=N1时,我们将前N-1场比赛都假设成赢,那么得分将有   3 ∗ ( N − 1 ) \ 3*(N-1)  3(N1),比较最后一场比赛,若S>T,得3分,S=T得2分,否则得0分
2.当进球数   S < N − 1 \ S<N-1  S<N1时,必须输一局,争取和局最多,此时,安排S场赢,1场输,剩下全和,这样总得分最高
最小得分:
1.当 S > T S>T S>T时,必须赢一局,因此最小得分的情况是赢一局,输T局(不超过N),剩下全和
2.当 S < = T S<=T S<=T时,有两种可能的情形:
2-1 必须赢一局,因此最小得分的情况是赢一局,输T局(不超过N),剩下全和
2-2 一局都没赢,尽最大可能输,剩余和
最小得分取两种情形下的较小者

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
int main(){
	LL S,T,N;
	
	while(cin >> S >> T >> N){
		LL minn=0;
		LL maxn=0;
		if(S>=N-1){
			maxn = 3*(N-1);
			if(S-(N-1)==T){
				maxn += 1;
			}else if(S-(N-1)>T){
				maxn += 3;
			}else{
				maxn += 0;
			}		
		}else{
			maxn = 3*S + (N-1-S)*1;
			if(T == 0){
				maxn += 1;
			}
		}	
		if(S>T){
			minn = 3 + 0LL*min(T,N) + 1*max(0LL,N-1-T);
		}else{
			LL t = 3 + 0LL*min(T,N) + 1*max(0LL,N-1-T);
			minn = min(max(N-(T-S),0LL)*1,t);
		}
		cout << maxn << " " << minn << endl;
	}
	
	return 0;
} 

P1403 [AHOI2005]约数研究

算法标签: 数论
注意点:   1 − n \ 1-n  1n所有正整数的约数的个数,等价于求正整数i的因子个数之和,因此只要累加 N i \frac{N}{i} iN即可

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
ll ans = 0;

int main(){
	int N;
	cin >> N;
	for(int i=1;i<=N;i++){
		ans += N/i;
	}
	cout << ans << endl;
	return 0;
}

P1604 B进制星球

算法标签: 数论 + 进制 + 高精

#include<bits/stdc++.h>
using namespace std;
int a[2005];
int b[2005];
int ans[2005];

int main(){
	int B;
	cin >> B;
	string s1,s2;
	cin >> s1 >> s2;
	int len1 = s1.size();
	int len2 = s2.size();
	for(int i=0;i<len1;i++){
		if(s1[i]>='A'){
			a[len1-i-1] = s1[i]-'A'+10;
		}else{
			a[len1-i-1] = s1[i]-'0';
		}
	} 
	for(int i=0;i<len2;i++){
		if(s2[i]>='A'){
			b[len2-i-1] = s2[i]-'A'+10;
		}else{
			b[len2-i-1] = s2[i]-'0';
		}
	} 
	int jw = 0;
	for(int i=0;i<max(len1,len2);i++){
		ans[i] = jw + a[i] + b[i];
		jw = ans[i] / B;
		ans[i] %= B; 
	}
	if(jw){
		ans[max(len1,len2)] = jw;
		for(int i=max(len1,len2);i>=0;i--){
			if(ans[i]>=10){
				printf("%c",ans[i]-10+'A');
			}else{
				printf("%c",ans[i]+'0');
			}
		}
	}else{
		for(int i=max(len1,len2)-1;i>=0;i--){
			if(ans[i]>=10){
				printf("%c",ans[i]-10+'A');
			}else{
				printf("%c",ans[i]+'0');
			}
		}
	}
	return 0;
} 

P1348 Couple number

算法标签: 数论 + 枚举
注意点: 首先,我们观察平方数1,4,9,16…,它们两两之间的差为奇数1,3,5,7…,这意味着所有的奇数都可以表达成两个平方数之差,接下来我们考察因式分解下   ( x + y ) ( x − y ) , ( x + y ) \ (x+y)(x-y),(x+y)  (x+y)(xy),(x+y)   ( x − y ) \ (x-y)  (xy)具有相同的奇偶性,由于之前讨论的是奇数的情形,那么现在讨论偶数情况下,两个偶数相乘必为4的倍数,因此所有是4的倍数的数字也符合情况,最后枚举输出结果

#include<bits/stdc++.h>
using namespace std;
const int maxn = 1e7;
bool hashT[2*maxn+5];
int main(){
	int a,b;
	cin >> a >> b;
	int cnt = 0;
	for(int i=a;i<=b;i++){
		if(abs(i)%4 == 0 || abs(i)%2==1){
			cnt++;
		}
	}
	cout << cnt << endl;
	return 0;
} 

P1855 榨取kkksc03

算法标签: 动态规划 + 背包
注意点: 三维背包

#include<bits/stdc++.h>
using namespace std;
int dp[201][201];
int m[201];
int t[201];

int main(){
	int n,M,T;
	cin>>n >>M >>T;
	for(int i=0;i<n;i++){
		cin >> m[i];
		cin >> t[i];
	}
	dp[0][0]=0;
	for(int i=0;i<n;i++){
		for(int j=M;j>=m[i];j--){
			for(int k=T;k>=t[i];k--){
				dp[j][k]=max(dp[j][k],dp[j-m[i]][k-t[i]]+1);
			}
		}
	}
	cout << dp[M][T] << endl;
	
	return 0;
} 

P1679 神奇的四次方数

算法标签: 数论 + 背包
注意点: 本题既可以用动态规划的方法来完成,也可以采用DFS数字搜索来完成

#include<bits/stdc++.h>
using namespace std;
int a[18];
int dp[100001];
int main(){
	memset(dp,0x3f3f3f3f,sizeof(dp));
	int m;
	cin >> m;
	for(int i=1;i<=17;i++){
		int tmp=1;
		for(int j=0;j<4;j++){
			tmp = tmp * i;	
		}
		a[i]=tmp;
	}
	dp[0]=0;
	for(int i=1;i<=17;i++){
		for(int j=a[i];j<=m;j++){
			dp[j]=min(dp[j],dp[j-a[i]]+1);
		}
	}
	cout << dp[m] << endl;
	return 0;
}

P1889 士兵站队

算法标签: 数论 + 中位数
注意点: 这道题考察的是对中位数的理解,中位数必须满足所有的点到中点的距离之和最短,这正好符合题意(移动的步数最少)

#include<bits/stdc++.h>
using namespace std;
int x[10005];
int y[10005];
int main(){
	int n;
	cin >> n;
	for(int i=1;i<=n;i++){
		cin >> x[i] >> y[i];
	}
	sort(x+1,x+n+1);
	for(int i=1;i<=n;i++){
		x[i] -= i;
	}
	sort(x+1,x+n+1);
	sort(y+1,y+n+1);
	int ans1,ans2;
	if(n%2==0){
		ans1 = (x[n/2]+x[n/2+1])/2;
		ans2 = (y[n/2]+y[n/2+1])/2;
	}else{
		ans1 = x[n/2+1];
		ans2 = y[n/2+1];
	}

	long long cnt = 0; 
	for(int i=1;i<=n;i++){
		cnt += (abs(x[i]-ans1));
		cnt += (abs(y[i]-ans2));
	}
	cout << cnt << endl;
	return 0;
} 

P1706 全排列问题

算法标签: 数论 + DFS
注意点: 深入一层,就枚举一个未被选过的数,加入数组中,直到层数=N,搜索完毕,输出结果

#include<bits/stdc++.h>
using namespace std;
int N;
int a[15];
bool hashT[15];

void dfs(int depth){
	if(depth == N){
		for(int i=0;i<N;i++){
			cout << setw(5) << a[i];
		}
		printf("\n");
	}else{
		for(int i=1;i<=N;i++){
			if(!hashT[i]){
				hashT[i] = true;
				a[depth] = i;
				dfs(depth+1);
				hashT[i] = false;
			}
		}
	}
}

int main(){
	cin >> N;
	dfs(0);
	
	return 0;
}

P2118 [NOIP2014 普及组] 比例简化

算法标签: 数论 + 枚举
注意点: 从1-L分别枚举A’和 B’,使得新的分数比之前大且两数之差最小

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

int main(){
	LL A,B,L;
	LL u,v;
	cin >> A >> B >> L;
	LL minn = LONG_MAX;
	for(int i=1;i<=L;i++){
		for(int j=1;j<=L;j++){
			LL t1 = 1LL*A*j;
			LL t2 = 1LL*B*i;
			if(t1<=t2 && t2-t1<minn){
				minn = t2-t1;
				u = i;
				v = j;
			}
		}
	}
	LL g = __gcd(u,v);
	u /= g;
	v /= g;
	cout << u << " " << v << endl;
	return 0;
} 

P2719 搞笑世界杯

算法标签: 数论 + 动态规划
注意点: dp[i][j]表示有i个A,j个B时最后2个相同的概率。

#include<bits/stdc++.h>
using namespace std;
double f[1255][1255];

int main(){
	int n;
	cin >> n;
	n = n/2;
	for(int i=2;i<=n;i++){
		f[i][0] = f[0][i] = 1.0;
	}
	
	for(int i=1;i<=n;i++){
		for(int j=1;j<=n;j++){
			f[i][j] = (f[i-1][j] + f[i][j-1])/2.0;
		}
	}
	printf("%.4lf\n",f[n][n]);
	return 0;
} 

P2651 添加括号III

算法标签: 数论
注意点:   a [ 2 ] \ a[2]  a[2]一定在分母,   a [ 1 ] 、 a [ 3 ] . . . a [ n ] \ a[1]、a[3]...a[n]  a[1]a[3]...a[n]一定在分子,因此只要判断   a [ 2 ] \ a[2]  a[2]能否被其余数整除即可

#include<bits/stdc++.h>
using namespace std;
int a[10005];

int main(){
	int t;
	scanf("%d",&t);
	while(t--){
		int n;
		scanf("%d",&n);
		for(int i=0;i<n;i++){
			scanf("%d",&a[i]);
		}
		int t = a[1];
		bool flag = false;
		for(int i=0;i<n;i++){
			if(i!=1){
				int g = __gcd(a[i],t);
				t /= g;
			}
			if(t==1){
				flag = true;
				break;
			}
		} 
		if(flag){
			printf("Yes\n");
		}else{
			printf("No\n");
		}
	}
	return 0;
}

P2660 zzc 种田

算法标签: 数论 + gcd
注意点: 每次种最大的正方形,因此不断辗转相除,直到最后一块地为正方形为止

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
ll ans = 0;

int main(){
	ll a,b;
	cin >> a >> b;
	ll ans = 0;
	if(a<b){
		swap(a,b);
	}
	while(a%b){
		ans += (a/b) *b*4;
		ll tmp = b;
		b = a%b;
		a = tmp;
	}
	ans += 1LL*a*4;
	cout << ans <<endl;
	return 0;
}

P5834 [USACO19DEC]MooBuzz S

算法标签: 数论 + 模拟

#include<bits/stdc++.h>
using namespace std;
int a[]={0,1,2,4,7,8,11,13,14};
int main(){
	long long N;
	cin >> N;
	long long ans1 = N/8;
	long long ans2 = N%8;
	ans1 *= 15;
	if(ans2 == 0){
		cout << ans1-1 << endl;
	}else{
		long long ans = 0;
		ans += ans1;
		ans += a[ans2];
		cout << ans << endl;	
	}
	return 0;
} 

P6068 『MdOI R1』GCD? GCD!

算法标签: 数论 + 素数筛

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

int main(){
	int T;
	cin >> T;
	while(T--){
		int n;
		cin >> n;
		int u = -1;
		for(int i=1;i<=sqrt(n);i++){
			if(n%i==0){
				if(i>=6){
					u = max(u,n/i);
				}else if(n/i>=6){
					u = max(i,u);
				}
			}
		}
		cout << u << endl;	
	}
	
	return 0;
}

P1163 银行贷款

算法标签: 数论 + 二分
注意点: 二分利率,计算还款数额与题目所给数值之差是否在0.001内

#include<bits/stdc++.h>
using namespace std;
int n,x,m;
double S;

double calcu(double r){
	double ans = n*1.0;
	for(int i=1;i<=m;i++){
		ans *= (1.0+r);
		ans = ans - x;
	}
	return ans;
}

double binary(double left,double right){
	if(fabs(right-left)<1e-5){
		return left;
	}else{
		double mid = (left+right)/2.0;
		double res = calcu(mid);
		if(res<=0){
			return binary(mid,right); 
		}else{
			return binary(left,mid);
		}	
	}
}

int main(){
	cin >> n >> x >> m;
	S = (x*m*1.0)/(n*1.0);
	double ans = binary(0.0,3.0);
	ans *= 100.0;
	printf("%.1lf\n",ans);
	return 0;
}
  • 2
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值