目录
UVA 10673 Play with Floor and Ceil
一,多元一次不定方程
CodeForces 681B Economy Game
题目:
Description
Kolya is developing an economy simulator game. His most favourite part of the development process is in-game testing. Once he was entertained by the testing so much, that he found out his game-coin score become equal to 0.
Kolya remembers that at the beginning of the game his game-coin score was equal to n and that he have bought only some houses (for 1 234 567 game-coins each), cars (for 123 456 game-coins each) and computers (for 1 234 game-coins each).
Kolya is now interested, whether he could have spent all of his initial n game-coins buying only houses, cars and computers or there is a bug in the game. Formally, is there a triple of non-negative integers a, b and c such that a × 1 234 567 + b × 123 456 + c × 1 234 = n?
Please help Kolya answer this question.
Input
The first line of the input contains a single integer n (1 ≤ n ≤ 109) — Kolya's initial game-coin score.
Output
Print "YES" (without quotes) if it's possible that Kolya spent all of his initial n coins buying only houses, cars and computers. Otherwise print "NO" (without quotes).
Sample Input
Input
1359257
Output
YES
Input
17851817
Output
NO
这个题目就是暴力枚举而且,当然了,是二重循环而不是三重循环。
唯一的技巧就是,在内存循环之前,先判断了n的奇偶性,因为(56,1234)=2
加了这一句,就从30ms变成了15ms
代码:
#include<iostream>
using namespace std;
int main()
{
int n;
while (cin>>n)
{
bool flag = false;
for (int a = 0; n>=0; a++)
{
if (n % 2==0)
{
for (int b = 0; b <= n / 123456; b++)
{
if ((n - 56 * b) % 1234 == 0)
{
flag = true;
break;
}
}
}
if (flag)break;
n -= 1234567;
}
if (flag)cout << "YES";
else cout << "NO";
cout << endl;
}
return 0;
}
二,佩尔方程
1,佩尔方程(I型)
2,佩尔方程定理(I型)
(1)如果d是正整数,不是完全平方数,那么一定有解,
如果是最小解,那么所有的解
都可以用最小解的幂求出:
(2)如果d<=0,或者d是完全平方数,那么一定有x=0或y=0
3,佩尔方程 x^2-61*y^2=1
下面我将编程求解它的最小解
如果直接枚举x和y的话,大约需要10秒
代码:
#include<iostream>
using namespace std;
int main()
{
long long x = 2, y = 0, flag = 3; //flag=x*x-61*y*y-1
while (flag)
{
if (flag > 0)
{
flag -= 61 * (2 * y + 1);
y++;
}
else
{
flag += 2 * x + 1;
x++;
}
}
cout << x << " " << y << " " << x*x;
system("pause>nul");
return 0;
}
如果先数学求解的话,自然会快一些。
首先,x必定是奇数,y必定是偶数
设x=s*2+1,y=t*2
那么s(s+1)=61t*2
分解:有2种情况
第一种,s=61*a^2,s+1=b^2,那么b^2-61*a^2=1,与x,y是最小解矛盾。
第二种,s=a^2,s+1=61*b^2,那么a^2-61*b^2=-1,化成这种佩尔方程了。
如果这个方程有解的话,原方程也有解,而且这个方程的解比原方程的解小得多。
2个方程是几乎差不多的,代码只需要略略改改就可以了。
代码:
#include<iostream>
using namespace std;
int main()
{
long long x = 2, y = 0, flag = 5;
while (flag)
{
if (flag > 0)
{
flag -= 61 * (2 * y + 1);
y++;
}
else
{
flag += 2 * x + 1;
x++;
}
}
cout << x*x * 2 + 1;
system("pause>nul");
return 0;
}
这个不需要1秒就可以算完。
最后,附上PDF的截图
4,佩尔方程(II型)
目前没有有效判断是否有解的方法。
如果是最小解,那么所有的解
都可以用最小解的幂求出:
5,力扣 2485. 找出中枢整数
给你一个正整数 n ,找出满足下述条件的 中枢整数 x :
1 和 x 之间的所有元素之和等于 x 和 n 之间所有元素之和。
返回中枢整数 x 。如果不存在中枢整数,则返回 -1 。题目保证对于给定的输入,至多存在一个中枢整数。
示例 1:
输入:n = 8
输出:6
解释:6 是中枢整数,因为 1 + 2 + 3 + 4 + 5 + 6 = 6 + 7 + 8 = 21 。
示例 2:
输入:n = 1
输出:1
解释:1 是中枢整数,因为 1 = 1 。
示例 3:
输入:n = 4
输出:-1
解释:可以证明不存在满足题目要求的整数。
提示:
1 <= n <= 1000
思路:
x^2 = (n+1)n/2
class Solution {
public:
int pivotInteger(int n) {
int x=sqrt((n+1)*n/2);
return x*x==(n+1)*n/2?x:-1;
}
};
实际上,可以求出二元不定方程 x^2 = (n+1)n/2 的所有解。
分2种情况:
(1)n=2a^2, n+1=b^2, x=ab
b^2-2a^2=1
I型佩尔方程,最小解b=3,a=2,所有解可以表示成b+ac = (3+2c)^k , c=sqrt(2), k=1,2,3,4....
(2)n=a^2,n+1=2b^2, x=ab
a^2-2b^2=-1
II型佩尔方程,最小解a=1,b=1,所有解可以表示成a+bc =(1+c)^k,c=sqrt(2), k=1,3,5,7....
利用组合数学继续求解:
(1)n=((3+2c)^2k + (3-2c)^2k - 2)/4 , k=1,2,3,4....
(2)n=((3+2c)^k + (3-2c)^k - 2)/4 , k=1,3,5,7....
综上,n的所有解是n=((3+2c)^k + (3-2c)^k - 2)/4 , k=1,2,3,4....
回到题目本身,枚举n的前几个解:
int main()
{
double c = sqrt(2);
double d1 = 3 + c * 2, d2 = 3 - c * 2;
double p1 = 1, p2 = 1;
cout.setf(ios::fixed);
for (int i = 0; i < 20; i++) {
p1 *= d1, p2 *= d2;
cout << (p1 + p2 - 2) / 4 << ",";
}
return 0;
}
输出:
1.000000,8.000000,49.000000,288.000000,1681.000000,9800.000000,57121.000000,332928.000000,1940449.000000,11309768.000000,65918161.000000,384199200.000000,2239277040.999999,13051463047.999994,76069501248.999969,443365544447.999817,2584123765440.999023,15061377048199.994141,87784138523760.968750,511643454094367.812500
验证了确实都是整数之后,只需要打印整数部分:
1,8,49,288,1681,9800,57121,332928,1940449,11309768,65918161,384199200,-2147483648,-2147483648,-2147483648,-2147483648,-2147483648,-2147483648,-2147483648,-2147483648,
二次编码
class Solution {
public:
int pivotInteger(int n) {
map<int,int>m;
m[1] = 1, m[8] = 6, m[49] = 35, m[288] = 204;
return m[n]?m[n]:-1;
}
};
验证过,果然AC了。
三,勾股数、幂和方程
1,勾股数
(1)勾股数的通项公式:2uvd、(u^2-v^2)d、(u^2+v^2)d,其中(u,v)=1且u,v一奇一偶
(2)若x^2、y^2、z^2成等差数列,则x,y,z都是奇数,进一步可推出通项公式:
(3)4个平方和不可能成等差数列
2,x^4+y^4=z^2(无穷递降法)
证明只有xy=0的解。
假设存在其他解,那么最小解可以表示成,其中u是奇数,v是偶数
根据可得,
根据可得,
所以
所以
这样就得到了更小的解,矛盾!
3,其他幂和方程
(1)x,y,z两两互素,,则
的解为
,
其中a>b>0,(a,b)=1,2|ab
(2)
4,力扣 483. 最小好进制
以字符串的形式给出 n
, 以字符串的形式返回 n
的最小 好进制 。
如果 n
的 k(k>=2)
进制数的所有数位全为1,则称 k(k>=2)
是 n
的一个 好进制 。
示例 1:
输入:n = "13" 输出:"3" 解释:13 的 3 进制是 111。
示例 2:
输入:n = "4681" 输出:"8" 解释:4681 的 8 进制是 11111。
示例 3:
输入:n = "1000000000000000000" 输出:"999999999999999999" 解释:1000000000000000000 的 999999999999999999 进制是 11。
提示:
n
的取值范围是[3, 1018]
n
没有前导 0
class Solution {
public:
long long smallestGoodBase(long long n) { // solve k^m = n*k - n +1
//m>3
for (long long k = 2; k*k*k < n; k++) {
if (n%k != 1)continue;
long long km = n - (n - 1) / k;
while (km%k == 0)km /= k;
if (km == 1)return k;
}
//m=3
long long k = sqrt(n - 3.0 / 4);
if (k>1 && k*k + k + 1 == n)return k;
//m=2
return n - 1;
}
string smallestGoodBase(string n) {
long long nn = StrToInt(n.data(), 10);
long long ans = smallestGoodBase(nn);
char *s = new char[20];
int len = IntToStr(ans, 10, s);
return string(s);
}
};
四,环形跑道运动问题
0,背景思路
如果涉及到多个对象的运动问题,只需要先把AB的所有重合时间算出来,再把AC的所有重合时间算出来,再把AD的所有重合时间算出来......
所以下面的各种场景,我们都要把所有重合时间算出来。
1,连续空间,连续时间,追及问题
问题:跑道长为L,A每秒运动x,B每秒运动y,x>y,同向运动,A到B的距离是c,求所有重合时间。
PS:L x y c是大于0的实数,下同。
不定方程:xt-yt=c+nL,其中n是自然数,下同,求正实数t
分析:无论给的x y c L是多少,一定有无穷多解。
解:t=(c+nL)/(x-y),n是任意自然数。
2,连续空间,连续时间,相遇问题
问题:跑道长为L,A每秒运动x,B每秒运动y,相向运动,A到B的距离是c,求所有重合时间。
不定方程:xt+yt=c+nL,求正实数t
分析:无论给的x y c L是多少,一定有无穷多解。
解:t=(c+nL)/(x+y),n是任意自然数。
3,连续空间,离散时间,同时运动,追及问题
PS:对于一些回合制游戏,或者考虑兔子这样一蹦一蹦的,可以用离散时间描述。
问题:跑道长为L,每回合AB同时运动,A运动x,B运动y,x>y,同向运动,A到B的距离是c,求所有重合时间。
不定方程:xm-ym=c+nL,求正整数m
分析:对于不同的x y c L,m可能有唯一解,可能有无穷多解,也可能无解
4,连续空间,离散时间,同时运动,相遇问题
问题:跑道长为L,每回合AB同时运动,A运动x,B运动y,相向运动,A到B的距离是c,求所有重合时间。
不定方程:xm+ym=c+nL,求正整数m
分析:对于不同的x y c L,m可能有唯一解,可能有无穷多解,也可能无解
5,连续空间,离散时间,依次运动,追及问题
问题:跑道长为L,每回合A先运动x,B再运动y,同向运动,A到B的距离是c,求所有重合时间。
PS:这里的x和y的大小关系是不定的,当然,x=y时自然是无解的。
A追上B的不定方程:xm-ym=c-x+zL,其中z是整数,下同,求正整数m
B追上A的不定方程:xm-ym=c+zL,求正整数m
分析:第一个不定方程可以化成第二个不定方程。第二个不定方程的z是>=0还是<0完全取决于x-y的正负性
6,连续空间,离散时间,依次运动,相遇问题
问题:跑道长为L,每回合A先运动x,B再运动y,相向运动,A到B的距离是c,求所有重合时间。
A追上B的不定方程:xm+ym=c-x+nL,求正整数m
B追上A的不定方程:xm+ym=c+nL,求正整数m
7,离散空间,离散时间,同时运动,追及问题
问题:跑道长为K格,每回合AB同时运动,A运动u格,B运动v格,u>v,同向运动,A到B的距离是w格,求所有重合时间。
不定方程:um-vm=w+nK
8,离散空间,离散时间,同时运动,相遇问题
问题:跑道长为K格,每回合AB同时运动,A运动u格,B运动v格,相向运动,A到B的距离是w格,求所有重合时间。
不定方程:um+vm=w+nK
9,离散空间,离散时间,依次运动,追及问题
问题:跑道长为K格,每回合A先运动u格,B再运动v格,同向运动,A到B的距离是w格,求所有重合时间。
PS:K u v w是正整数,下同
A追上B的不定方程:um-vm=w-u+zK
B追上A的不定方程:um-vm=w+zK
10,离散空间,离散时间,依次运动,相遇问题
问题:跑道长为K格,每回合A先运动u格,B再运动v格,相向运动,A到B的距离是w格,求所有重合时间。
PS:K u v w是正整数,下同
A追上B的不定方程:um+vm=w-u+nK
B追上A的不定方程:um+vm=w+nK
11,符号对照表
已知量: L x y c是大于0的实数,K u v w是正整数
变量: n是自然数,z是整数
所求变量: t是正实数t, m是正整数
五,其他不定方程
UVA 10673 Play with Floor and Ceil
题目:
我看网上基本上都是用欧几里得做的。。。
设s=x/k,那么,x=s*k+t,0≤t<k
那么方程化为s*k+t=p*k+q*(k+(t>0))
如果t=0,那么s=p+q,取p=s,q=0
如果t>0,那么s*k+t=(p+q)*k+q,取p=s-t,q=t
所以上面2种情况是一样的。
代码:
#include<iostream>
#include<stdio.h>
using namespace std;
int main()
{
int n, x, k;
scanf("%d", &n);
while (n--)
{
scanf("%d%d", &x, &k);
printf("%d %d\n", k - x%k, x%k);
}
return 0;
}
方程abc=a!+b!+c!
题目:求方程abc=a!+b!+c!的所有解
其中abc是三位数,三位分别为a、b、c
只需要一个求阶乘的函数即可。
代码:
#include<iostream>
using namespace std;
int fac[]={1,1,2,6,24,120,720,5040,40320,362880};
int main()
{
for (int a = 1; a < 10; a++)for (int b = 0; b < 10; b++)for (int c = 0; c < 10; c++)
if (a * 100 + b * 10 + c == fac[a] + fac[b] + fac[c])cout << a << b << c << endl;
cout << "end";
system("pause>nul");
return 0;
}
求出145是唯一解
方程abc=a!+b!+c!的拓展
对于任意正整数n,各位数字阶乘后等于n本身,这样的n有多少个?
首先可以确定n的范围,100<=n<=2999999
然后可以枚举出结果:
145 40585 是仅有的2个解
51Nod 2167 ProjectEuler 34
145 是一个古怪的数字,因为 1! + 4! + 5! = 1 + 24 + 120 = 145。
输入n,求所有小于等于n且各位阶乘和等于本身的数字之和。
注意,1! = 1 和 2! = 2 并不算古怪的数字。
Input
输入第一行组数T, 接下来T行,每行一个整数n。 (1 <= T <= 5) (1 <= n <= 100000000)
Output
对于每组数据,输出一个数,表示所有小于等于n,各位阶乘和等于本身的数字之和。
Sample Input
1
145
Sample Output
145
#include<iostream>
using namespace std;
int main()
{
int t,n;
cin>>t;
while(t--)
{
cin>>n;
cout<<(n>=145)*145+(n>=40585)*40585<<endl;
}
return 0;
}
理工科硕士爸爸解一年级数学题急出汗
填入1-9这9个数字,使得各个圆内数字之和都是13
解法:
六,不定方程组
1,四人成锁
最强大脑第12季的项目。
对于每个颜色,首先算一下12个数字,表示每个选手的操作对4个锁的影响,填充对角线是1的矩阵。
随便举个例子:
1 2 3 4
2 1 5 6
8 1 1 3
0 4 7 1
再计算出4个数字,表示离目标还有多少距离。
随便举个例子:
1 1 0 0
那么,需要求解的不定方程组就是
a(1 2 3 4)+b(2 1 5 6)+c(8 1 1 3)+d(0 4 7 1)=(1 1 0 0)+(10u 10v 10s 10t)
这里有4个方程组,8个未知数,其中u v s t可以是任意自然数,abcd是要求的变量。
求解示例:
计算机求解:
#include <iostream>
#include<vector>
using namespace std;
//检查Ax=b(mod p)是否成立
bool check(vector<vector<int>>&A,vector<int>&x,vector<int>&b,int p)
{
for(int i=0;i<A.size();i++){
int s=-b[i];
for(int j=0;j<A[i].size();j++)s+=A[i][j]*x[j];
if(s%p)return false;
}
return true;
}
//暴力求解Ax=b(mod p)
vector<int> SolveModP(vector<vector<int>>A,vector<int>b,int p)
{
vector<int>ans=A[0];
int m=1;
for(int i=0;i<ans.size();i++)m*=p;
for(int k=0;k<m;k++){
int kk=k;
for(int i=0;i<ans.size();i++)ans[i]=kk%p,kk/=p;
if(check(A,ans,b,p))return ans;
}
return ans;
}
//暴力求解孙子定理,根据mod2和mod5的结果,求mod10
int sunzi(int m2,int m5)
{
if(m5%2==m2)return m5;
return m5+5;
}
//求解Ax=b(mod 10)
vector<int> SolveMod10(vector<vector<int>>A,vector<int>b)
{
vector<int>ans2=SolveModP(A,b,2);
vector<int>ans5=SolveModP(A,b,5);
vector<int>ans;
for(int i=0;i<ans2.size();i++)ans.push_back(sunzi(ans2[i],ans5[i]));
return ans;
}
//求解四人成锁
void myMain()
{
vector<vector<int>>A(4,vector<int>(4));
vector<int>ori(4),old,news,b(4);
for(int i=0;i<4;i++)cin>>ori[i]; //记录初始值
news=old=ori;
for(int i=0;i<4;i++){ //依次点击4个按钮,记录每次的刷新值
for(int j=0;j<4;j++){
cin>>news[j];
A[j][i]=(news[j]+10-old[j])%10;
}
old=news;
}
for(int i=0;i<4;i++){ //记录目标值
cin>>b[i];
b[i]=(b[i]+10-ori[i])%10;
}
//记得复位单个颜色
vector<int> ans = SolveMod10(A,b);
for(auto x:ans)cout<<x<<" ";
cout<<endl;
}
int main() {
myMain();
return 0;
}
输入:
3 2 0 2
4 8 7 4
6 9 6 3
3 6 7 7
3 4 9 8
6 0 6 8
输出:
8 5 5 5
2,多元一次同余方程组
四人成锁其实就是一种多元一次同余方程组。
对于形如Ax=b(mod c)的方程组,其中A是n*n的已知矩阵,b是n*1的已知列向量,c是已知整数,求x,求解的大致步骤和线性代数中求解Ax=b一样。
但是,同余方程有时没办法直接除,所以这种方法并不通用。
我想了一种通用解法,首先把c表示成单素数幂的乘积,然后求解若干个Ax=b(mod 单素数幂)这样的方程组,最后用剩余定理求Ax=b(mod c)的解。