数学是程序竞赛中常见的题目,并且很容易和其他题目一起出,作为基础,还是得尽快掌握。
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
const int MAXN = 505;
char a1[MAXN], a2[MAXN];
int ans[MAXN];
int len1, len2;
void add(char* a1, char* a2) {
int len1 = strlen(a1);
int len2 = strlen(a2);
int jin = 0;
int yu = 0;
int i, j;
//从短的那边加,一旦短的加完,那么第一个for停止
for (i = len2 - 1,j=len1-1;i >= 0;i--,j--) {
int num = a1[j] - '0' + (a2[i] - '0')+jin;
yu = num % 10;
jin = num / 10;
ans[j + 1] = yu;
}
//从长的那边加,短的加完了,要算长的那边,比如例子
//1111111111111111111111111
//9999999999
for (j;j >= 0;j--) {
int num = a1[j] - '0' + jin;
yu = num % 10;
jin = num / 10;
ans[j + 1] = yu;
}
//上面没算ans[0],所以我们这边特别算,下面也有对0的特判
if (jin > 0)ans[0] = jin;
}
int main() {
cin>> a1 >> a2;
len1 = strlen(a1);
len2 = strlen(a2);
if (len1 > len2) {
add(a1, a2);
}
else
add(a2, a1);
int maxn = max(len1, len2);
if (ans[0] != 0)cout << ans[0];
for (int i = 1;i <= maxn;i++) {
cout << ans[i];
}
}
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
const int MAXN =5000;
char a1[MAXN], a2[MAXN];
int a[MAXN], b[MAXN];
int ans[MAXN];
int main() {
cin >> a1 >> a2;
a[0] = strlen(a1), b[0] = strlen(a2);
//倒序模拟
for (int i = 1;i <= a[0];i++)a[i] = a1[a[0] - i] - '0';
for (int i = 1;i <= b[0];i++)b[i] = a2[b[0] - i] - '0';
for (int i = 1;i <= a[0];i++) {
for (int j = 1;j <= b[0];j++) {
ans[i + j - 1] += a[i] * b[j];
}
}
int len = a[0] + b[0];
for (int i = 1;i <= len;i++) {
if (ans[i] >= 10)ans[i + 1] += ans[i] / 10, ans[i] %= 10;
}
//除去前缀0
while (ans[len] == 0 && len > 1)len--;
for (int i = len;i >= 1;i--)cout << ans[i];
return 0;
}
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
const int MAXN =5000;
const int mod = 200907;
int N;
//等差数列
long long getadd(long long n, long long a1,long long d) {
return (a1 + (n - 1) * d)%mod;
}
//等比数列,快速幂
long long getmult(long long n, long long a1,long long q) {
long long res = a1;
long long base = q;
n--;//因为等比数列的是n-1次方
while (n) {
if (n & 1) {
res *= base; res %= mod; }
base *= base;
base %= mod;
n >>= 1;
}
return res%mod;
}
int main() {
cin >> N;
while (N--) {
long long a, b, c,K;
cin >> a >> b >> c >> K;
if (a - b == b - c) {
cout << getadd(K, a, b - a) << endl;
}
else {
cout << getmult(K, a, b / a) << endl;
}
}
}
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
const int MAXN =5000;
const int mod = 200907;
int N;
//快速幂模板,因为只取最后一位,只要取模10
int fastm(int a, int n) {
a %= 10;
int base = a;
int res = 1;
while (n) {
if (n & 1) {
res *= base;
res %= 10;
}
base *= base;
base %= 10;
n >>= 1;
}
return res %= 10;
}
int main() {
cin >> N;
while (N--) {
int n;
cin >> n;
cout << fastm(n, n) << endl;
}
return 0;
}
discuss里大佬的博客,证明前4位怎么得到的。http://www.cnblogs.com/WArobot/p/6810504.html
为何可以转为矩阵乘法,因为斐波那契是递归数列,矩阵不像常数,只能表示一个数,矩阵可以记录很多数,比如斐波那契数列,矩阵的00元素记录当前值,01记录前一个值,10和11没用,只是为了方便乘法。然后灵魂就是后面那个递归矩阵,他乘一下就可以代表递归的数运算一下,然后用快速幂。
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
int n;
//定义二维矩阵
struct mat {
int m[2][2];
mat() {
memset(m, 0, sizeof m);
}
};
//定义矩阵乘法运算,这里是2维,把2改为n便是n维
mat mult(mat m1, mat m2) {
mat res;
for (int i = 0;i < 2;i++) {
for (int j = 0;j < 2;j++) {
for (int k = 0;k < 2;k++) {
res.m[i][j] = (res.m[i][j] + m1.m[i][k] * m2.m[k][j])%10000;
}
}
}
return res;
}
//矩阵快速幂
mat fastm(mat a, int n) {
mat res;
res.m[0][0] = 1, res.m[1][1] = 1;
while (n) {
if (n & 1) {
res = mult(res, a);
}
a = mult(a, a);
n >>= 1;
}
return res;
}
int main() {
while (cin >> n) {
//n==0特判
if (n == 0) {
cout << 0 << endl;
}
//n<=39打表
else if (n <= 39) {
int a = 1, b = 1;
for (int i = 1;i <= n-2;i++) {
int tmp = a;
a = a + b;
b = tmp;
}
cout << a << endl;
}
//n>=40,运用矩阵快速幂求后4位,找到运算公式求前4位
else {
mat mm;
mm.m[0][0] = 1, mm.m[0][1] = 1, mm.m[1][0] = 1;
mat ans2 = fastm(mm, n - 1);
double ans1 = log10(1.0 / sqrt(5.0)) + log10((1 + sqrt(5.0)) / 2) * n;
ans1 =ans1- (int)ans1;
int ans = (int)(pow(10.0, ans1) * 1000);
cout << ans << "...";
//前置补0,用printf,自己补零可能会出错。
printf("%04d\n", ans2.m[0][0]);
}
}
}
gcd:欧几里得算法以及欧几里得算法扩展
欧几里得b站大佬视频:https://www.bilibili.com/video/BV1Ra4y1h723/?spm_id_from=333.788.videocard.0
欧几里得扩展b站大佬视频:https://www.bilibili.com/video/BV1bp4y1S7bW?from=search&seid=6067462148398361649
lcm:两数乘积除去gcd
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
int n;
long long gcd(long long a, long long b) {
return b == 0 ? a : gcd(b, a % b);
}
long long lcm(long long a, long long b) {
return a/ gcd(a, b) * b ;
}
int main() {
cin >> n;
while (n--) {
int num;
cin >> num;
long long f;
num--;
cin >> f;
while (num--) {
long long l;
cin >> l;
//gcd要求大数在前面,小数在后面
if (f > l)
f = lcm(f, l);
else f = lcm(l, f);
}
cout << f << endl;
}
}
推荐2篇大佬博客
1.https://blog.csdn.net/swordholy/article/details/4423543
2.https://blog.csdn.net/u011815404/article/details/88423181?utm_medium=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-3.channel_param&depth_1-utm_source=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-3.channel_param
先1后2,慢慢看,对欧几里得扩展会有更深的认识。
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
typedef long long ll;
int n;
ll gcd(ll a, ll b) {
return b == 0 ? a : gcd(b, a % b);
}
ll lcm(ll a, ll b) {
return a/ gcd(a, b) * b ;
}
ll t0,k0;
//引用可以很好的同时求出t,k
void extend_gcd(ll a, ll L, ll& t, ll& k) {
if (L == 0) {
t = 1, k = 0;
return;
}
extend_gcd(L, a % L, t, k);
//这里是由欧几里得gcd推理得到,还算简单
ll tmp = t;
t = k;
k = tmp - (a / L) * k;
}
int main() {
ll x, y, m, n, L;
while (cin >> x >> y >> m >> n >> L) {
ll a = m - n;
ll b = y - x;
//扩展gcd处理不了负数,所以取反,a和b是对应的
if (a < 0) {
a = -a, b = -b; }
extend_gcd(a, L, t0, k0);
//d是gcd(a,L)
ll d = a * t0 + L * k0;
//下面的看博客,对我这种新手有点难度
if (b % d != 0) {
cout << "Impossible" << endl;
continue;
}
//这里不懂可以再去看看扩展欧几里得如何得到最小解答
cout << (t0 * (b / d)%(L/d) +(L/d)) % (L/d) << endl;
}
}
上面一题分析透彻,这一题只要自己理清题意,得到等式就可以利用欧几里得扩展了。
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
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) {
return a/ gcd(a, b) * b ;
}
void extend_gcd(ll B, ll mod, ll& k, ll& a) {
if (mod == 0) {
k = 1, a = 0;
return;
}
extend_gcd(mod, B%mod, k, a);
ll tmp = k;
k = a;
a = tmp - (B/mod) * a;
}
int main() {
int N;
cin >> N;
while (N--) {
ll n, B;
cin >> n >> B;
ll mod = 9973;
ll k, a;
//欧几里得扩展的前2个参数得是正数,后面2个算是x,y,可以为负数
extend_gcd(B, mod, k, a);
cout << ((k * n) % mod + mod) % mod << endl;
}
}
推荐博客:https://blog.csdn.net/weixin_41707869/article/details/90107418
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
typedef long long ll;
int n;
const int MAXN = 1e5 + 5;
const int mod = 1e9 + 7;
ll mul[MAXN], sum[MAXN];
ll gcd(ll a, ll b) {
return b == 0 ? a : gcd(b, a % b);
}
ll lcm(ll a, ll b) {
return a/ gcd(a, b) * b ;
}
void extend_gcd(ll a, ll b, ll& x, ll& y) {
if (b == 0) {
x = 1, y = 0;
return;
}
extend_gcd(b, a%b, x, y);
ll tmp = x;
x = y;
y = tmp - (a/b) * y;
}
//逆元
ll mod_inverse(ll a, ll b) {
ll x, y;
extend_gcd(a, b, x, y);
//防止负数
return (x % b + b) % b;
}
int main() {
int t;
cin >> t;
sum[1] = 0;
mul[1] = 1;
for (int i = 2;i <= MAXN-1;i++) {
sum[i] = sum[i - 1] + i;
mul[i] = mul[i - 1] * i % mod;
}
while (t--) {
int n;
//输入数据得用scanf或者快读,不然会超时
scanf("%d",&n);
if (n <= 4) {
cout << n << endl;continue;
}
//upper_bound(begin,end,tar)在数列求种tar的上界,返回地址,所以减去sum+1
ll k = upper_bound(sum + 1, sum + MAXN, n)-sum-1;
ll yu = n - sum[k];ll ans;
if (yu == k) {
ans = mul[k + 2] * mod_inverse(2, mod) % mod * mod_inverse(k + 1, mod)%mod;
}
else {
ans = mul[k + 1] * mod_inverse(k +1- yu, mod) % mod;
}
printf("%lld\n", ans);
}
}
线性欧拉筛大佬博客:https://www.cnblogs.com/liuwenyao/p/9931230.html
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
const int MAXN = 1e4 + 5;
bool visit[MAXN] = {
0 };
int prime[MAXN];
int cnt=0;
//欧拉筛
void init() {
for (int i = 2;i < MAXN;i++) {
if (!visit[i])
prime[++cnt] = i;
for (int j = 1;j <= cnt, prime[j] * i < MAXN;j++) {
visit[prime[j] * i] = true;
if (i % prime[j] == 0)break;
}
}
}
int main() {
init();
int n;
while (cin >> n) {
//二分找第一个小于n/2的,然后看看另一个数是不是素数
int k = upper_bound(prime + 1, prime + cnt + 1, n / 2)-(prime+1);
//cout << k << endl;
while (k) {
if (visit[n - prime[k]] == false) {
cout << prime[k] << " " << n - prime[k] << endl;
break;
}
k--;
}
}
}
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
const int MAXN = 2e4 + 5;
bool visit[MAXN] = {
0 };
int maxprime[MAXN];
int cnt=0;
//类似埃式筛
void init() {
//坑:1算质数,0也算质数
maxprime[1] = 1;
maxprime[0] = 0;
for (int i = 2;i < MAXN;i++) {
//遇到质数就更新所有比他大的合数,使得最大质因子为该数
if (!maxprime[i]) {
for (int j = i;j < MAXN;j += i)maxprime[j] = i;
}
}
}
int main() {
init();
int t;
//多组输入,一个坑,有个坑数据 1 0 答案 0
while (cin >> t) {
int maxa = 0;
int maxi = -1;
for (int i = 0;i < t;i++) {
int a;
cin >> a;
if (maxprime[a] > maxa) {
maxa = maxprime[a]; maxi = a; }
}
cout << maxi << endl;
}
}
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
const int MAXN = 1e6 + 5;
bool visit[MAXN] = {
0 };
int prime[MAXN];
int cnt=0;
//欧拉筛得到前1e6个数中的质数
void init() {
for (int i = 2;i < MAXN;i++) {
if (!visit[i])
prime[++cnt] = i;
for (int j = 1;j <= cnt && prime[j] * i < MAXN;j++) {
visit[i * prime[j]] = true;
if (i % prime[j] == 0)break;
}
}
}
int main() {
init();
int t;
cin >> t;
int k = 0;
while (t--) {
bool flag = false;
long long n;
cin >> n;
//观察前面1e6个数的质数是否成为它的平方数
for (int i = 1;i <= cnt&&prime[i]<=n;i++) {
if (n % prime[i] == 0) {
n /= prime[i];
if (n % prime[i] == 0) {
flag = true;
break;
}
}
}
//如果在筛选后还大于1e6,那么只有1.素数 2.素数乘素数 3.素数的平方
//最多是2次方,因为经过前面质数删选,1-1e6的质数都被删去,剩下的数就是大于1e6的素数,如果3次方,会大于1e18
if (n > (long long)1e6) {
long long a = sqrt(n);
if (n == a * a)flag = true;
}
//注意格式
cout << "Case " << ++k << ": ";
if (flag)cout << "No" << endl;
else cout << "Yes" << endl;
}
}
#include
#include
#define wbx 1000005
__int64 a[wbx];
#include
//如果数量最多的糖果记为N,其余总和为s,如果是s>=N-1将数量最多的作为挡板,然后把所有排好序的糖果依次插入每个区域内,肯定不相邻
//如果s
int main()
{
__int64 n,m,i;
scanf("%I64d",&n);
while(n--)
{
memset(a,0,sizeof(a));
__int64 max=-99;
__int64 sum=0;
scanf("%I64d",&m);
for(i=1;i<=m;i++)
{
scanf("%I64d",&a[i]);
sum+=a[i];
if(a[i]>max)
max=a[i];
}
__int64 sum1=sum+1-max;
if(sum1>=max)
printf("Yes\n");
else
printf("No\n");
}
return 0;
}
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
const int MAXN = 1e5 + 5;
int num[MAXN];
int ans[MAXN];
int c, n;
int be, en;
void init() {
memset(num, 0, sizeof num);
memset(ans, 0, sizeof ans);
be = -1, en = -1;
}
//抽屉原理,N个数,N-1个盒子,必然有2个数在一起
//把c作为N,因为n>=c,所以对于n个数求前缀和取余c,必然有2个相同
int main() {
std::ios::sync_with_stdio(false);
while (cin >> c >> n) {
if (c == 0 && n == 0)break;
init();
map<int, int>m;
ans[0] = 0;
//如果前缀取余直接为0,那么就找到了,所以记m[0]为0
m[0] = 0;
for (int i = 1;i <= n;i++) {
cin >> num[i];
}
for (int i = 1;i <= n;i++) {
ans[i] = (ans[i - 1] + num[i])%c;
if(m.find(ans[i])==m.end())
m[ans[i]] = i;
else {
be = m[ans[i]], en = i;
break;
}
}
if (be == -1 && en == -1) {
cout << "no sweets" << endl;
}
else {
for (int i = be+1;i <= en-1;i++) {
cout << i << " ";
}
cout << en << endl;
}
}
}
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
const int MAXN = 1e5 + 5;
int num[MAXN];
int ans[MAXN];
bool visit[MAXN];
int c, n;
void init() {
memset(num, 0, sizeof num);
memset(ans, 0, sizeof ans);
memset(visit, 0, sizeof visit);
ans[0] = 0;
visit[0] = true;
}
//还是抽屉原理
int main() {
int t;
cin >> t;
while (t--) {
init();
bool flag = false;
int n, m;
cin >> n >> m;
for (int i = 1;i <= n;i++) {
cin >> num[i];
}
for (int i = 1;i <= n;i++) {
ans[i] = (ans[i - 1] + num[i])%m;
if (visit[ans[i]] == true) {
flag = true;
break;
}
else {
visit[ans[i]] = true;
}
}
if (flag == true)
cout << "YES" << endl;
else cout << "NO" << endl;
}
}
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
typedef long long ll;
const int MAXN = 1e5 + 5;
int prime[MAXN];
int cnt = 0;
//这题说白了就是在m,n中遍历每个点,如果x,y互质那么就可以看见
//getp得到素数
void getp(int n) {
cnt = 0;
for (int i = 2;i * i <= n;i++) {
if (n % i == 0) {
prime[cnt++] = i;
while (n % i == 0)n /= i;
}
}
if (n > 1)prime[cnt++] = n;
}
//容斥原理,读者看不懂,可以看一下容斥原理三集合,然后自己往后推理
ll getf(ll m) {
//求不互质的数
int t = 0;
ll que[1005];
//这里定-1为了后面ans+=计算方便
que[t++] = -1;
for (int i = 0;i < cnt;i++) {
int k = t;
for (int j = 0;j< k;j++) {
//读者可以定一个5*5的图,自己看,这里每一次计算,都相当于几个质数相乘,而正负则表明在容斥公式中的符号
//容斥定理求集合,先得加上所有单个子集,然后减去所有2个子集得交集,然后加上所有3个子集得交集。。。等等往后推
//这里每个quei都是prime数组相乘结果,prime相乘就相当于交集了,比如质数2,3,相乘为6,那么我们在2,3基础上减去6的倍数,就是减去交集
que[t++] = (-1) * que[j] * prime[i];
}
}
ll ans = 0;
for (int i = 1;i < t;i++) {
//这里m/que[i]表示que[i]的倍数,因为que[i]都是prime相乘的结果,如果m=12,que=2,那么一除,表示有6个2的倍数,que=3的话,一除,表示4个3的倍数,同理往后。
ans += (m / que[i]);
}
return ans;
}
int main() {
int t;
ll a, b,res;
scanf_s("%d", &t);
while (t--) {
scanf_s("%lld%lld", &a, &b);
if (a > b) {
ll tmp = a;
a = b;
b = tmp;
}
res = 0;
for (int i = 1;i <= a;i++) {
getp(i);
//这里读者不妨自己推理为何要b减去,因为我们getf得到的是反过来的,是不互斥的总集合
res += (b - getf(b));
}
printf("%lld\n",res);
}
}
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
typedef long long ll;
const int MAXN = 1e5 + 5;
ll prime[MAXN];
ll que[MAXN];
int cnt = 0;
void getp(ll n) {
cnt = 0;
for (ll i = 2;i * i <= n;i++) {
if (n % i == 0) {
prime[cnt++] = i;
while (n % i == 0)n /= i;
}
}
if (n > 1)prime[cnt++] = n;
}
ll getf(ll m) {
int t = 0;
que[t++] = -1;
for (int i = 0;i < cnt;i++) {
int k = t;
for (int j = 0;j< k;j++) {
que[t++] = (-1) * que[j] * prime[i];
}
}
ll ans = 0;
for (int i = 1;i < t;i++) {
ans += (m / que[i]);
}
return ans;
}
int main() {
int t;
ll a, b,n,res;
int k = 0;
scanf_s("%d", &t);
while (t--) {
scanf_s("%lld%lld%lld", &a, &b,&n);
res = 0;
getp(n);
//b-getf(b),求前b的互质的数,再减去前a-1的互质的数
res = (b - getf(b))-(a-1-getf(a-1));
cout << "Case #" << ++k << ": ";
printf("%lld\n",res);
}
}
都是求大数斐波那契数列,hdu3117上面已经写过,用到矩阵快速幂。
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
typedef long long ll;
const int MAXN = 125;
int c1[MAXN + 1], c2[MAXN + 1];
//母函数模板题,读者自己找关于母函数的定义
void init() {
//按照正常思路展开母函数,先对系数初始化,c2记录临时变量
for (int i = 0;i <= MAXN;i++) {
c1[i] = 1;
c2[i] = 0;
}
//i表示第i个多项式,k+=i,表示x的幂每次递增i
for (int i = 2;i <= MAXN;i++) {
//j表示从相乘2个多项式中左边多项式的关于x的幂
for (int j = 0;j <= MAXN;j++) {
//k表示2个多项式中右边的关于x的幂
for (int k = 0;k + j <= MAXN;k += i) {
//2个幂相乘,得到j+k的幂,为何+=,因为c1存的相当于是系数,c1[j]表示x的j次幂的系数
c2[j + k] += c1[j];
}
}
//每次乘完2个多项式都要把c1和c2转化一下
for (int i = 0;i <= MAXN;i++) {
c1[i] = c2[i];
c2[i] = 0;
}
}
}
int main() {
int n;
init();
while (cin >> n) {
cout << c1[n] << endl;
}
}
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
typedef long long ll;
const int MAXN = 15;
double c1[MAXN + 1], c2[MAXN + 1];
double jiec[MAXN + 1];
int num[MAXN];
int n, m;
void getjiec() {
jiec[0] = 1.0;
jiec[1] = 1;
for (int i = 2;i <= MAXN;i++) {
jiec[i] = i * 1.0 * jiec[i - 1];
}
}
int main() {
getjiec();
while (cin >> n >> m) {
for (int i = 1;i <= n;i++) {
cin >> num[i];
}
memset(c1, 0, sizeof(c1));
memset(c2, 0, sizeof(c2));
//初始化第一个多项式,作为乘法的左边的数
for (int i = 0;i <= num[1];i++) {
c1[i] = 1.0/jiec[i];
c2[i] = 0;
}
//从第二个多项式开始分别和第一个多项式乘
for (int k = 2;k <= n;k++) {
for (int i = 0;i <= m;i++) {
//多了限制条件
for (int j = 0;j <= num[k] && j + i <= m;j++) {
c2[j + i] += c1[i] / jiec[j];
}
}
for (int i = 0;i <= m;i++) {
c1[i] = c2[i];
c2[i] = 0;
}
}
printf("%.0lf\n", c1[m] * jiec[m]);
}
}
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
typedef long long ll;
const int MAXN = 36;
ll c[MAXN];
//卡特兰数的代码
//虽说有点抽象,但是就相当于给你一堆1和0,让你整理一个数列使得对任意前k项,1的数目大于或等于0的数目。
//这题就是把向上走比作0,向右走比作1,向右的数目必须大于等于0,不然就不是。
//同理,对判断括号是否合理比如()()合理,(()不合理,也是一样,把左括号比作1,右括号比作0.
void init() {
c[0] = 1;
for (int i = 1;i <= 35;i++) {
for (int j = 0;j < i;j++) {
c[i] += c[j] * c[i - j-1];
}
}
}
int main() {
init();
int n;
int k = 0;
while (cin >> n) {
if (n == -1)break;
cout << ++k << " " << n << " " << 2 * c[n]<<endl;
}
}
令h(0)=1,h(1)=1,catalan数满足递推式[1]:
h(n)= h(0)*h(n-1)+h(1)*h(n-2) + … + h(n-1)h(0) (n>=2)
例如:h(2)=h(0)h(1)+h(1)h(0)=11+11=2
h(3)=h(0)h(2)+h(1)h(1)+h(2)h(0)=12+11+21=5
另类递推式[2]:
h(n)=h(n-1)(4n-2)/(n+1);
递推关系的解为:
h(n)=C(n,2n)*(2n-1) (n=0,1,2,…)
递推关系的另类解为:
h(n)=c(2n,n)-c(2n,n+1)(n=0,1,2,…)
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
typedef long long ll;
const int MAXN =105;
const int mod = 20090126;
ll c[MAXN][MAXN];
ll s[MAXN][MAXN];
ll jiec[MAXN];
void init() {
s[0][0] = 1;
jiec[0] = 1;
//初始化得到阶乘
for (int i = 1;i <= MAXN - 1;i++) {
jiec[i] = jiec[i - 1] * i % mod;
s[i][0] = 0;
}
//得到斯大林数
for (int i = 1;i <= MAXN - 1;i++) {
for (int j = 1;j <= MAXN - 1;j++) {
s[i][j] = (s[i - 1][j - 1] + j * s[i - 1][j]%mod)%mod;
}
}
}
int main() {
init();
int t;
scanf_s("%d", &t);
while (t--) {
int n;
scanf_s("%d", &n);
ll ans = 0;
//把平局的人装进盒子,不平局的看成不同盒子。
for (int i = 1;i <= n;i++) {
ans =(ans+ s[n][i] * jiec[i] )% mod;
}
printf("%lld\n", ans);
}
}
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
typedef long long ll;
int main() {
int t;
cin >> t;
while (t--) {
int n, m;
cin >> n >> m;
//一个人最多去m颗,所以如果石头是m+1倍数的话,甲无论取几颗,乙取到m+1颗就行
if (n % (m + 1) == 0)cout << "second" << endl;
else cout << "first" << endl;
}
}
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
typedef long long ll;
int main() {
int n, m;
while (cin >> n >> m) {
if (n == 0 && m == 0)break;
//读者自己画图找一下规律,对于左下角3个状态,有P为N,全N为P
if (n % 2 == 0) {
cout << "Wonderful!" << endl;
continue;
}
else {
if (m % 2 == 0)cout << "Wonderful!" << endl;
else cout << "What a pity!" << endl;
}
}
}
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
typedef long long ll;
const int MAXN = 105;
int a[105];
//尼姆游戏:n堆,每次取任意一堆的任意个石子,用异或运算
int main() {
int n;
while (cin >> n) {
if (n == 0)break;
int sum = 0, ans = 0;
for (int i = 1;i <= n;i++) {
cin >> a[i];
sum ^= a[i];
}
if (sum == 0)cout << 0 << endl;
else {
for (int i = 1;i <= n;i++) {
//不等式左边表示除了a[i]其他的异或和,如果小于右边,就把右边的数拿到和左边一样
if ((sum ^ a[i]) < a[i])ans++;
}
cout << ans << endl;
}
}
}
大佬博客:https://www.cnblogs.com/graytido/p/10771907.html
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
typedef long long ll;
const int MAXN = 1005;
int sg[1005],s[1005];
int f[15] = {
1,2,3,5,8,13,21,34,55,89,144,233,377,610,987 };
void getsg() {
sg[0] = 0;
sg[1] = 0;
for (int i = 1;i <= 1000;i++) {
sg[i] = i;
memset(s, 0, sizeof(s));
for (int j = 0;j < 15 && f[j] <= i;j++) {
s[sg[i - f[j]]] = 1;
}
for (int j = 0;j <= i;j++) {
if (s[j] == 0) {
sg[i] = j;break;
}
}
}
}
int main() {
getsg();
int n, m, p;
while (cin >> n >> m >> p) {
if (n == 0 && m == 0 && p == 0)break;
if ((sg[n] ^ sg[m] ^ sg[p] )== 0)cout << "Nacci" << endl;
else cout << "Fibo" << endl;
}
}
这里分析奇异局势与非奇异局势的转换。首先奇异局势在这里是P(必败),那么我们处在奇异局势时,必败,我们处在非奇异时,能不能转到奇异局势,见大佬博客:https://blog.csdn.net/Jason_crawford/article/details/52129969?utm_medium=distribute.pc_relevant_t0.none-task-blog-BlogCommendFromMachineLearnPai2-1.channel_param&depth_1-utm_source=distribute.pc_relevant_t0.none-task-blog-BlogCommendFromMachineLearnPai2-1.channel_param
我们可以知道非奇异能够成为奇异,换句话说,因为奇异时P,我们非奇异能变为P,那么我们非奇异就是N(必胜)
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
typedef long long ll;
const int MAXN = 1005;
//代码实现
int main() {
int n, m;
while (cin >> n >> m) {
int a = max(n, m);
int b = min(n, m);
double k = (double)(a - b);
double gold = (1 + sqrt(5)) / 2;
int test = (int)(k * gold);
if (test == b)cout << 0 << endl;
else cout << 1 << endl;
}
}