51CTO博客开发
有一种很有意思的游戏,就是有物体若干堆,可以是火柴棍或是围棋子等等均可。两个人轮流从堆中取物体若干,规定最后取光物体者取胜。这是我国民间很古老的一个游戏,别看这游戏极其简单,却蕴含着深刻的数学原理。下面我们来分析一下要如何才能够取胜。(一)巴什博奕(Bash Game):只有一堆n个物品,两个人轮流从这堆物品中取物,规定每次至少取一个,最多取m个。最后取光者得胜。
void Pollard(long long n); void Factor(long long n) { long long d = 2; while (true) { if (n % d == 0) { Pollard(d); Pollard(n / d); return; } d++; } } void Pollard(long long n) { if (n <= 0) printf
/*题意:给出一个数,若为合数则求出其最靠近的两边的质数之差(距离),若是质数,则输出0即可 解题:阿拉斯托散筛法的应用,试模板的题目 63msACc++代码*/ #include <iostream> #include <cstdio> #include <cstring> #include <cmath> #include<algorith
/*题意:给出p和a,如果p不是素数且a^p === a(mod p)的话,输出yes,否者输出no 解题:蒙哥马利模平方计算+拉宾米勒素数判定方法 0msACc++代码*/ #include <iostream> #include <cstdio> #include <cstring> #include <cmath> #include<al
/*题意:给出一个数,注意有可能是负数,这个数能表示为x=b^p,求最大的p 解题:这道题比较卡精度,所以直接用__int64,负数的话就输入后处理一下,用Pollard分解一下这个数,获得这个数得标准分解式, 即这个数的素数乘积表达式,问题就是求组成这个数的这些素数的幂数的最大公约数,注意负数的答案只能是奇数,若得到的答案是偶数, 需要不断除以2直至获得一个奇数答案为止。 16msACc++代码
int_type Montgomery(int_type n,int_type p,int_type m) { //蒙哥马利法快速计算(n^p)%m的值 int_type k = 1; n%=m; while(p!=1) { if(0!=(p&1))k=(k*n)%m; n=(n*n)%m; p>>=1; } return(n*k)%m; } bool Miller_rabin
/*大牛的思路: 典型的中国剩余定理,但是这里是非互质情况下的中国剩余定理。 解题思路: 1.因为(a1,a2,a3,a4,….,ak)不一定互质,所以不能够直接用中国剩余定理。 2.x=r1+a1*k1,x=r2+a2*k2,所以有r1+a1*k1=r2+a2*k2,化简后得到 a1*k1=(r2-r1) mod(a2); 用扩展欧几里得可以得到最小的k1,所以x=r1+a1*k1+a1*a2/
#include <iostream> #include <cstdio> #include <cstring> #include <cmath> using namespace std; int GetRemainder(int baseNum, int power, int modelNum) { //判断各个值正确性 baseNum %= mo
/*解题思路:分解为十进制的一位,每位求余一次。即设str[0--n]为大数(0为个位,1为十位,2为百位,...) 有 ans[0] = str[0] % b; ans[1] = str[1] * 10 % b; . . . ans[n] = str[n]*10^n % b; 这里要解决对10的n次方求余的问题,其实很简单,设temp[k]=10^k%b,必有 temp[k] = temp[k]
#include <iostream> #include <cstdio> #include <cstring> #include <cmath> using namespace std; int n,k,m; int main() { while(scanf("%d %d %d",&n,&k,&m),n||m||k) { i
/*这题一开始用约瑟环的递推公式做,发现无限的超时,果断打表一看,前五十如下: 1 1 2 1 3 3 4 1 5 3 6 5 7 7 8 1 9 3 10 5 11 7 12 9 13 11 14 13 15 15 16 1 17 3 18 5 19 7 ... 规律出来了,先用等比求和算出在第几个循环里面,再用等差数列递推式算出是该循环的第几个值*/ #include <iostream
1.约定x%y为x取模y,即x除以y所得的余数,当xx^y表示x的y次方。乘方运算的优先级高于乘除和取模,加减的优先级最低。 见到x^y/z这样,就先算乘方,再算除法。A/B,称为A除以B,也称为B除A。 若A%B=0,即称为A可以被B整除,也称B可以整除A。A*B表示A乘以B或称A乘B,B乘A,B乘以A……都一样。时,x%y=x,所有取模的运算对象都为整数。<>复
#include<cstdio> #include<iostream> #include<cstring> #include<algorithm> using namespace std; int c[3500],w[3500],n,m,dp[13000]; int main() { int i,j; while(scanf("%d %d",&
题意:有六种石头,给你各种石头的个数,每种石头的价值就是其输入的顺序,求是否有一种方法可以分这些石头为两个相等的部分。解题思路:多重背包,其实说是可行性背包更贴切,只不过这里用的是多重背包的模板,因为每一种石头都有一定的数量,用多重背包来做好一点。就是以总价值的一半为下标的上界(总价值可被2乘除时),待dp完成后查看,查当容量为总价格的一半的时候,是否存在可取的石头数。#include<cs
题意:已知一个猪仔储钱罐空载时的质量和满载时的质量,给出猪仔储钱罐中有可能出现的硬币种类,每种硬币都有自身的质量和价值,问当一个猪仔储钱罐满载时内面最少有的硬币的总价值。解题思路:这是一个完全背包问题,因为硬币是可以无限装,那么所求的是最小值,就把初始状态都设为无限大,只有0状态为0,然后只有现态不为无穷大的时候,才就去找次态与现态+1的最小值,然后就是模板的事了。#include<cstd
#include <cstdio>#include <cmath>#include <algorithm>using namespace std;const int inf = (1<<30)-1;const int maxn =&
1013ms G++代码 #include<iostream> #include<cstdio> #include<cstring> #include<string> #include<algorithm> #include<cmath> using namespace std; const int NUM = 100010;
题意:星星的等级计算方法是看它左下方星星的数目来定的。根据y坐标递增(若y坐标相等则x坐标递增)的顺序给出一堆星星的坐标,请计算所有等级(n-1个等级)的星星数。解题思路:由于是按一定顺序给出星星,那么我们读进的星星不会有前者等级大于后者的情况出现。情况只有两种:①前者在后者的左下方;②前者不在后者的左下方。每一次读进星星我们只能靠x来判断是属于那种情况,所以如果有一个表可以记录横坐标为0--x的
题意:给你一个数组,求出这个数组的所有循环移位状态的逆序数,求出最小值解题思路:对于一个数组中求逆序数是比较简单的,其实就是把每个数前面的大于它的数的数目加起来就是逆序数了。利用树状数组加速的话,就是把没输入一个数就先查询再更新,查询出的值是比当前数要小或相等的 且 在当前数前面的数的数目,假如前面有i个数,查询值为k,则当前数前面的比当前数大的数目为i-k,把这些值加起来就是
求多个矩形面积的并0msC++代码 #include<iostream> #include<cstdio> #include<cstring> #include<string> #include<algorithm> #include<cmath> using namespace std; const int NUM
题意:给出多个矩形的左上角和右下角坐标,求这些矩形面积的并,即相重的面积只算一次解题思路:首先离散化:把读进来的坐标变为一条竖边,一个矩形有两个竖边:左竖边和右竖边,左竖边用与制造覆盖,右竖边用于消除覆盖,要标记好哪些是左竖边,哪些是右竖边。建一个结构体数组来存放竖边,并按照竖边的很坐标升序排序(从小到大)。把所有的纵坐标用一个数组存放,并升序排序,离散化结束。建一个线段树用于查看目前那些纵坐标被
跟1264差不多,但是需要注意就是只计算覆盖度大于等于2的长度,要记住修改时要修改所有子节点3109msC++代码#include<iostream> #include<cstdio> #include<cstring> #include<string> #include<algorithm> #include<cmath>
这题本来不想写题解的,太容易了,就赤裸裸的最小生成树,不过由于我没考虑会有重边输入,所以我就wa了几遍,看了别人的评论后才改过ac了细节是魔鬼吖!!!prime算法也531ms过的,估计克鲁斯卡尔算法不优化的话会超时,毕竟是25000条边531ms代码#include<iostream>int g[505][505];int prime(int n){&n
又一赤裸裸最小生成树,普利姆过了,不过时间复杂度感觉没比库鲁斯卡尔好多少,也许库鲁斯卡尔会好一点243ms代码#include<iostream>int g[105][105];int lowest[105];int flag[105];int prime(int n){ int i,j,k,min,sum=0;&n
第一次做最小生成树,由于点只有100个,故采用普利姆算法会合理一点,两题都差不多就是1863的每次读入点后检验一下最小权值是否小于0就ok了1863的0ms代码如下(1233的就改一改就好了)#include<iostream>#include<string>int g[105][105];bool flag[105];int lowest[1
#include<cstdlib>#include<iostream>#include<string>#include<queue>#include<vector>#include<map>const int INF = 1<<26;using namespace&
#include<cstdlib>#include<iostream>#include<cstring>using namespace std;int mj[202][202];int result[202];int n,m;void dij(int x){ int j,f
/*判断负环的两种方法:Spfa思想:如果存在一个点进入队列的次数超过N次,则存在负环。bellman_ford思想:对所有的边进行v-1 松弛即如果 dis[u]+map[u][v] < dis[v] 则 dis[v] = dis[u]+map[u][v] 若v-1次松弛之后还能进行松弛,
可以用广搜,也可以用最短路来求,我用了最短路用了Dijkstra+优先队列,15ms就过了,第一次用优先队列优化Dijkstra算法大概时间复杂度就m*log(n)左右15ms代码#include<cstdlib>#include<iostream>#include<cstring>#include<queue>#include<vector&
Copyright © 2005-2024 51CTO.COM 版权所有 京ICP证060544号