抱歉,您的浏览器无法访问本站
本页面需要浏览器支持(启用)JavaScript
了解详情 >

技巧

1.getchar放回
ungetc(val, stdin);
2.二分查首位
#include <stdio.h>
#include <algorithm>
int a[1000000];
int main(void)
{
    int n, m;
    scanf("%d%d", &n, &m);
    int b[100000];
    for (int i = 0; i < n; i++)
    {
        scanf("%d", &a[i]);
    }
    for (int i = 0; i < m; i++)
    {
        scanf("%d", &b[i]);
    }
    int mid;
    int *temp;
    for (int i = 0; i < m; i++)
    {
        temp = std::lower_bound(a, a + n, b[i]);
        mid = temp - &a[0];
        if (std::binary_search(a, a + n, b[i]))
            printf("%d ", mid + 1);
        else if (a[0] == 0 && b[i] == 0)
            printf("1");
        else
            printf("-1 ");
    }
    return 0;
}
3.排序
std::sort(a, a + n);
4.最大公约数
std::__gcd(i, j);
5.最小公倍数
i * j / std::__gcd(i, j);
6.斐波那契博弈

有一堆个数为n的石子,游戏双方轮流取石子,满足:
1)先手不能在第一次把所有的石子取完;
2)之后每次可以取的石子数介于1到对手刚取的石子数的2倍之间(包含1和对手刚取的石子数的2倍)。
约定取走最后一个石子的人为赢家,求必败态。

结论:先手胜当且仅当n不是斐波那契数(n为物品总数)

7.威佐夫博弈

有两堆各若干个物品,两个人轮流从某一堆或同时从两堆中取同样多的物品,规定每次至少取一个,多者不限,最后取光者得胜。

我们有如下公式:a表示第一堆的个数,b表示第二堆的个数,c表示二者之差,当然a必须小于b;
再找规律的话我们会发现,a= c* 1.618

部分模板

素数筛法(运行时间约1.2s)

char pend[100000005];
int odd[7123456];
void count()
{
    int count = 1;
    /* 定义 */
    pend[1] = 1;    //特判
    for (int i = 2; i * i <= 100000005; i++)
    {
        if (!pend[i])
        {
            for (int j = i * i; j <= 100000005; j += i)
            {
                pend[j] = 1;
            }
        }
    }
    /* 线筛 */
    for (int i = 1; i < 100000005; i++)
    {
        if (!pend[i])
        {
            odd[count++] = i;
        }
    }
    /* 储存 */
    return;
}

螺旋数列

#include <stdio.h>
int main(void)
{
    int n;
    int value = 1;
    int i, j;
    scanf("%d", &n);
    int m[100][100];
    /* 数组大小 */
    for (i = 0; i < (n + 1) / 2; i++)
    {
        for (j = i; j < n - i; j++)
        {
            m[i][j] = value++;
        }

        for (j = i + 1; j < n - i; j++)
        {
            m[j][n - i - 1] = value++;
        }
        for (j = n - i - 2; j >= i; j--)
        {
            m[n - i - 1][j] = value++;
        }
        for (j = n - i - 2; j > i; j--)
        {
            m[j][i] = value++;
        }
    }
    for (int i = 0; i < n; i++)
    {
        for (int j = 0; j < n; j++)
        {/* 输出格式 */
            printf("%5d", m[i][j]) 
        }
        printf("\n");
    }

    return 0;
}
#include <stdio.h>
int main(void)
{
    int n;
    scanf("%d", &n);
    if (n == 0)
    {
        return 0;
    }
    int m = n + n - 1;
    int q = n - 1;
    int t = 1;
    int a[n][n];
    int *p;
    p = &a[0][0];
    int time = 1;
    for (int i = 0; i < (n + n - 1); i++)
    {
        if (time % 4 == 1)
        {
            for (int j = 0; j < q; j++)
            {
                *p = t;
                p += 1;
                t++;
                *p = t;
            }
        }
        else if (time % 4 == 2)
        {
            for (int j = 0; j < q; j++)
            {
                *p = t;
                p += n;
                t++;
                *p = t;
            }
        }
        else if (time % 4 == 3)
        {
            for (int j = 0; j < q; j++)
            {
                *p = t;
                p -= 1;
                t++;
                *p = t;
            }
        }
        else if (time % 4 == 0)
        {
            for (int j = 0; j < q; j++)
            {
                *p = t;
                p -= n;
                t++;
                *p = t;
            }
        }

        if (time % 2 && time != 1)
            q -= 1;
        time++;
    }
    for (int i = 0; i < n; i++)
    {
        for (int j = 0; j < n; j++)
        {
            printf("%5d", a[i][j]);
        }
        printf("\n");
    }
    return 0;
}

刺痛值

输入
第一行有两个用空格隔开的整数,分别代表 n 和 m。
第 22 到第 (n + 1) 行,每行一个整数,第 (i + 1) 行的整数 a_i代表第 i 件事的刺痛值 a_i。
输出
输出一行一个整数,表示连续 m 个刺痛值的和的最小值是多少。

#include <stdio.h>
int main(void)
{
    int n, m;
    scanf("%d%d", &n, &m);
    int a[n];
    for (int i = 0; i < n; i++)
    {
        scanf("%d", &a[i]);
    }
    int b = 0, min;
    for (int i = 0; i < n - m; i++)
    {
        b = 0;
        for (int j = 0; j < m; j++)
        {
            b += a[i + j];
        }
        if (b <= min || i == 0)
            min = b;
    }
    if (!m || !n)
    {
        min = 0;
    }
    else if(!(m - n))
    {
        for (int j = 0; j < m; j++)
        {
            b += a[j];
        }
        min = b;
    }
    printf("%d", min);
    return 0;
}

观察下面的数字金字塔。

写一个程序来查找从最高点到底部任意处结束的路径,使路径经过数字的和最大。每一步可以走到左下方的点也可以到达右下方的点。
7
3 8
8 1 0
2 7 4 4
4 5 2 6 5

#include <stdio.h>
#include <algorithm>
int a[1200][1200];
int b;
int sum;
int main(void)
{
    int m, t, o, temp;
    scanf("%d", &m);
    o = 1;
    for (int i = 0; i < m; i++)
    {
        for (int j = 0; j < o; j++)
        {
            scanf("%d", &a[i][j]);
        }
        o++;
    }
    t = m;
    for (int j = 0; j < m; j++)
    {
        for (int i = 0; i < t; i++)
        {
            temp = std::max(a[m - j][i], a[m - j][i + 1]);
            a[m - j - 1][i] += temp;
        }
        t--;
    }
    b = a[0][0];
    printf("%d\n", b);
    return 0;
}

火柴棒等式

#include <stdio.h>
int main()
{
    int a[2001] = {6}, b, c[10] = {6, 2, 5, 5, 4, 5, 6, 3, 7, 6}, s = 0, i, j;
    scanf("%d", &b);
    for (i = 1; i <= 2000; i++)
    {
        j = i;
        while (j >= 1) //求每个数所用的火柴棒
        {
            a[i] = a[i] + c[j % 10];
            j = j / 10;
        }
    }
    for (i = 0; i <= 1000; i++)
    {
        for (j = 0; j <= 1000; j++)
            if (a[i] + a[j] + a[i + j] + 4 == b)
                s++; //还有加号与等号
    }
    printf("%d", s);
    return 0;
}

彩票摇奖

in
2
23 31 1 14 19 17 18
12 8 9 23 1 16 7
11 7 10 21 2 9 31
out
0 0 0 0 0 1 1

#include <stdio.h>
int main(void)
{
    int n;
    scanf("%d", &n);
    int a[n + 2][7];
    int count;
    for (int i = 0; i < n + 1; i++)
    {
        for (int j = 0; j < 7; j++)
        {
            scanf("%d", &a[i][j]);
        }
    }
    for (int i = 0; i < 7; i++)
    {
        a[n + 1][i] = 0;
    }
    for (int i = 1; i < n + 1; i++)
    {
        count = 0;
        for (int j = 0; j < 7; j++)
        {
            for (int k = 0; k < 7; k++)
            {
                if (a[i][j] == a[0][k])
                {
                    count++;
                }
            }
        }
        a[n + 1][7 - count]++;
    }
    for (int i = 0; i < 7; i++)
    {
        printf("%d", a[n + 1][i]);
        if (i != 6)
        {
            printf(" ");
        }
    }
    return 0;
}

移动字符串

in
1
qwe
out
rxf

#include <stdio.h>
#include <string.h>
int main(void)
{
    int n;
    scanf("%d", &n);
    char a[60];
    scanf("%s", &a);
    int m = strlen(a);
    for (int i = 0; i < n; i++)
    {
        for (int j = 0; j < m; j++)
        {
            if (a[j] == 'z')
            {
                a[j] = 'a';
            }
            else if (a[j] == 'Z')
            {
                a[j] = 'A';
            }
            else
            {
                a[j]++;
            }
        }
    }
    puts(a);
    return 0;
}

dp

#include <stdio.h>
#include <algorithm>
int main()
{
    int w[110], val[110];
    int dp[110][110];
    int t, m, res = -1;
    scanf("%d%d", &t, &m);/* t为时间,m为数目 */
    for (int i = 1; i <= m; i++)
    {/* 时间,价值 */
        scanf("%d%d", &w[i], &val[i]);
    }
    for (int i = 1; i <= m; i++)
    {
        for (int j = t; j >= 0; j--)
        {
            if (j >= w[i])
            {/* dp */
                dp[i][j] = std::max(dp[i - 1][j - w[i]] + val[i], dp[i - 1][j]);
            }
            else
            {
                dp[i][j] = dp[i - 1][j];
            }
        }
    }
    printf("%d", dp[m][t]);
    return 0;
}

杨辉三角

#include <stdio.h>
int a[21][21];
int main(void)
{
    int n = 0, count = 1;
    scanf("%d", &n);
    a[0][0] = a[1][0] = a[1][1] =1;
    for (int i = 0; i < n; i++)
    {
        for (int j = 0; j < count; j++)
        {
            if (i != 0 && i != 1)
            {
                a[i][j] = a[i - 1][j] + a[i - 1][j - 1];
            }
            printf("%d", a[i][j]);
            if (i - 1 != count)
            {
                printf(" ");
            }
        }
        printf("\n");
        count++;
    }
    return 0;
}

回文质数

// #include <stdio.h>
// char pend[100000005];
// void odd()
// {
//     int count = 1;
//     /* 定义 */
//     pend[1] = 1; //特判
//     for (int i = 2; i * i <= 100000005; i++)
//     {
//         if (!pend[i])
//         {
//             for (int j = i * i; j <= 100000005; j += i)
//             {
//                 pend[j] = 1;
//             }
//         }
//     }
//     /* 线筛 */
//     return;
// }
// int pend2(int num)
// {
//     int temp = num, ans = 0;
//     while (temp)
//     {
//         ans = ans * 10 + temp % 10;
//         temp /= 10;
//     }
//     if (ans == num)
//         return 1;
//     else
//         return 0;
// }
// int main(void)
// {
//     odd();
//     for (int i = 4; i < 100000000; i++)
//     {
//         if (pend2(i) && !pend[i])
//         {
//             printf("%d, ", i);
//         }
//     }
//     return 0;
// }

#include <stdio.h>
int odd[100000] = {};//略
int main(void)
{
    int a, b;
    scanf("%d%d", &a, &b);
    for (int i = 0; odd[i]; i++)
    {
        if (odd[i] <= b && odd[i] >= a)
        {
            printf("%d\n", odd[i]);
        }
    }
    return 0;
}

与 n 互质的第 k 个正整数。

#include <stdio.h>
#include <algorithm>
int a[1000005];
int main(void)
{
    int n, k, ans = 0;
    scanf("%d%d", &n, &k);
    for (int i = 0; i < n; ++i)
    {
        if (std::__gcd(i, n) == 1)
        {
            a[ans++] = i;
        }
    }
    printf("%d", (k - 1) / ans * n + a[(k - 1) % ans]);
    return 0;
}

深搜&质数

7 3 3 1 全部肋骨上的数字 7331 是质数;三根肋骨 733733 是质数;二根肋骨 73 是质数;当然,最后一根肋骨 7 也是质数。7331 被叫做长度 4 的特殊质数。

#include <stdio.h>
#include <math.h>
int a[4] = {1, 3, 7, 9};
int n;
int pend(int x)
{
    if (x == 1)
        return 0;
    if (x == 2)
        return 1;
    for (int i = 2; i <= sqrt(x); i++)
        if (x % i == 0)
        {
            return 0;
        }
    return 1;
}
void DFS(int k, int sum)
{
    int p;
    if (!(sum - n))
    {
        printf("%d\n", k);
    }
    else
    {
        for (int i = 0; i < 4; i++)
        {
            p = k * 10 + a[i];
            if (pend(p))
            {
                DFS(p, sum + 1);
            }
        }
    }
}
int main(void)
{
    scanf("%d", &n);
    DFS(2, 1);
    DFS(3, 1);
    DFS(5, 1);
    DFS(7, 1);
    return 0;
}

Nim博弈

#include <stdio.h>
int main(void)
{
    int t, n, val, ans;
    scanf("%d", &t);
    for (int i = 0; i < t; i++)
    {
        ans = 0;
        scanf("%d", &n);
        for (int j = 0; j < n; j++)
        {
            scanf("%d", &val);
            ans ^= val;
        }
        if (!ans)
        {
            printf("No\n");
        }
        else
        {
            printf("Yes\n");
        }
    }
    return 0;
}

阶乘之乘

#include <stdio.h>
int main(void)
{
    long long int n, ans = 0;
    scanf("%lld", &n);
    for (int i = n; i > 4; i--)
    {
        ans += i / 5 + i / 25 + i / 125 + i / 625 + i / 3125 + i / 15625 + i / 78125 + i / 390625 + i / 1953125 + i / 9765625 + i / 48828125;
        // while (temp)
        // {
        //     ans += temp / 5;
        //     temp /= 5;
        // }
    }
    printf("%lld", ans);
    return 0;
}

阶乘之和(Python)

num = int(input())
ans = 0
while num > 0 :
    fact = 1
    for i in range(1, num + 1):
        fact = fact * i
    ans += fact
    num = num - 1
print(ans)

取数游戏

有一个取数的游戏。初始时,给出一个环,环上的每条边上都有一个非负整数。这些整数中至少有一个0。然后,将一枚硬币放在环上的一个节点上。两个玩家就是以这个放硬币的节点为起点开始这个游戏,两人轮流取数,取数的规则如下:

(1)选择硬币左边或者右边的一条边,并且边上的数非0;

(2)将这条边上的数减至任意一个非负整数(至少要有所减小);

(3)将硬币移至边的另一端。

如果轮到一个玩家走,这时硬币左右两边的边上的数值都是0,那么这个玩家就输了。

如下图,描述的是Alice和Bob两人的对弈过程,其中黑色节点表示硬币所在节点。结果图(d)中,轮到Bob走时,硬币两边的边上都是0,所以Alcie获胜。

img

             (a)Alice  (b)Bob  (c)Alice   (d)Bob

现在,你的任务就是根据给出的环、边上的数值以及起点(硬币所在位置),判断先走方是否有必胜的策略。

#include <stdio.h>
int main()
{
    int n, a[30], left = 0, right = 0, flag1 = 1, flag2 = 1;
    scanf("%d", &n);
    for (int i = 0; i < n; i++)
    {
        scanf("%d", &a[i]);
    }
    for (int i = 0; i < n; i++)
    {
        if (a[left] && flag1)
        {
            left++;
        }
        else
        {
            flag1 = 0;
        }
        if (a[n - right - 1] && flag2)
        {
            right++;
        }
        else
        {
            flag2 = 0;
        }
        
    }
    if (left % 2)
    {
        printf("YES\n");
    }
    else if (right % 2)
    {
        printf("YES\n");
    }
    else
    {
        printf("NO\n");
    }
    return 0;
}

博弈B

游戏要求在一个有 nn 个顶点凸多边形上进行,这个凸多边形的 n-3n−3 条对角线将多边形分成 n-2n−2 个三角形,这 n-3n−3 条对角线在多边形的顶点相交。三角形中的一个被染成黑色,其余是白色。

双方轮流进行游戏,当轮到一方时,他必须沿着画好的对角线,从多边形上切下一个三角形。切下黑色三角形的一方获胜。胖子一看觉得确实很有趣,不如就一起玩玩吧。假设游戏由野猫先开始,那么野猫是否有必胜的策略呢?请写一个程序帮助野猫算一算。

#include <cstdio>
#include <algorithm>
using namespace std;
int n, a, b, c, aa, bb, cc;
void Sort(int &x, int &y, int &z)
{
    if (x > y)
        swap(x, y);
    if (x > z)
        swap(x, z);
    if (y > z)
        swap(y, z);
}
int main()
{
    scanf("%d", &n);
    //读入黑色三角形的三个顶点编号
    scanf("%d %d %d", &aa, &bb, &cc);
    //将三个编号从小到大排序,方便判断
    Sort(aa, bb, cc);
    //读入剩下的三角形编号
    for (int i = 2; i <= n - 2; i++)
        scanf("%d %d %d", &a, &b, &c);
    //判断黑色三角形是否能够第一刀切到
    if (aa + 1 == bb && bb + 1 == cc)
    { //编号连续代表三角形在外边
        puts("JMcat Win");
        return 0;
    }
    //当黑色三角形顶点最小是0是需要特判3种情况
    if (aa == 0)
    {
        if ((bb == 1 && cc == n - 1) || (bb == 1 && cc == 2) || (bb == n - 2 && cc == n - 1))
        {
            puts("JMcat Win");
            return 0;
        }
    }
    //这里思路已经说过
    if ((n - 2) % 2 == 1)
        puts("PZ Win");
    else
        puts("JMcat Win");
    return 0;
}

进制转化

#include <stdio.h>
#include <math.h>
#include <string.h>
int main(void)
{
    int val1, val2, val = 0;
    char num[50];
    scanf("%d", &val1);
    /* 输入进制 */
    scanf("%s", &num);
    scanf("%d", &val2);
    /* 输出进制 */
    int n = strlen(num) - 1;
    for (int i = 0; i < strlen(num); i++)
    {
        if (num[i] >= 'A')
        {
            val += pow(val1, n) * (num[i] - 'A' + 10);
        }
        else
        {
            val += pow(val1, n) * (num[i] - '0');
        }
        n--;
    }
    for (int i = 0; 1; i++)
    {
        if (val / pow(val2, i) <= 1)
        {
            n = i;
            break;
        }
    }
    char a[50];
    for (int i = 0; i < n; i++)
    {
        a[i] = (int)(val / pow(val2, n - i - 1)) % val2;
        if (a[i] >= 10)
        {
            a[i] = a[i] - 10 + 'A';
        }
        else
        {
            a[i] = a[i] + '0';
        }
    }
    for (int i = 0; i < n; i++)
    {
        printf("%c", a[i]);
    }
    return 0;
}

汉诺塔

#include <stdio.h>
int k = 1;
int move(char getone, int n, char putone)
{
    k++;
    return 0;
}
int hanoi(int n, char x, char y, char z)
{
    if (n == 1)
        move(x, 1, z);
    else
    {
        hanoi(n - 1, x, z, y);
        move(x, n, z);
        hanoi(n - 1, y, x, z);
    }
    return 0;
}
int main()
{
    int n, counter;
    scanf("%d", &n);
    counter = hanoi(n, 'A', 'B', 'C');
    printf("%d\n", k - 1);
    return 0;
}

全排列

7
-3
-2
-1
0
1
2
3

#include <iostream>
#include <algorithm>
using namespace std;
int main()
{
    int n;
    cin >> n;
    int a[100];
    for (int i = 0; i < n; i++)
    {
        a[i] = i + 1;
    }
    for (int i = 0; i < n; i++)
    {
        printf("%5d", a[i]);
    }
    printf("\n");
    while (next_permutation(a, a + n))
    {
        for (int i = 0; i < n; i++)
        {
            printf("%5d", a[i]);
        }
        printf("\n");
    }
    return 0;
}

3个数和为0

#include <stdio.h>
#include <algorithm>
#include <string.h>
int main(void)
{
    int n, count = 0, t;
    scanf("%d", &n);
    int a[10000], temp[3];
    int ans[10000][3];
    for (int i = 0; i < n; i++)
    {
        scanf("%d", &a[i]);
    }
    std::sort(a, a + n);
    for (int i = 0; i < n; i++)
    {
        for (int j = i + 1; j < n; j++)
        {
            for (int k = j + 1; k < n; k++)
            {
                if (a[i] + a[j] + a[k] == 0)
                {
                    printf("%d %d %d\n", a[i], a[j], a[k]);
                    count++;
                }
            }
        }
    }
    if (!count)
    {
        printf("No Solution\n");
    }
    return 0;
}

区间合并

5
5 6
1 5
10 10
6 9
8 10

#include <stdio.h>
#include <algorithm>
#include <string.h>
int main(void)
{
    int n, count = 0, t;
    scanf("%d", &n);
    int a[10000], temp[3];
    int ans[10000][3];
    for (int i = 0; i < n; i++)
    {
        scanf("%d", &a[i]);
    }
    std::sort(a, a + n);
    for (int i = 0; i < n; i++)
    {
        for (int j = i + 1; j < n; j++)
        {
            for (int k = j + 1; k < n; k++)
            {
                if (a[i] + a[j] + a[k] == 0)
                {
                    printf("%d %d %d\n", a[i], a[j], a[k]);
                    count++;
                }
            }
        }
    }
    if (!count)
    {
        printf("No Solution\n");
    }
    return 0;
}

数列有序

3 3
1 2 4
0 0

#include <stdio.h>
#include <algorithm>
#include <string.h>
int main(void)
{
    int n, count = 0, t;
    scanf("%d", &n);
    int a[10000], temp[3];
    int ans[10000][3];
    for (int i = 0; i < n; i++)
    {
        scanf("%d", &a[i]);
    }
    std::sort(a, a + n);
    for (int i = 0; i < n; i++)
    {
        for (int j = i + 1; j < n; j++)
        {
            for (int k = j + 1; k < n; k++)
            {
                if (a[i] + a[j] + a[k] == 0)
                {
                    printf("%d %d %d\n", a[i], a[j], a[k]);
                    count++;
                }
            }
        }
    }
    if (!count)
    {
        printf("No Solution\n");
    }
    return 0;
}

评论