基础枚举总结

基础枚举总结

前记:也是很基础的一个专题了,大多数还是暴力可解,当然也有不行的,最难的部分用到了线段树。。。从简单做起,这种专题一天就能搞完,过两天刷到难的专题,就不知道要多长时间才能刷完了。本专题持续更新。

【枚举】桐桐的计算

题目描述:
这个周末数学老师布置了一道有趣的题目,意思是:九头鸟(传说中的一种怪鸟,它有九个头、两只脚)、鸡和兔子关在一个笼子里。数数它们的头正好是100个,数数它们的脚也正好是100只。老师让桐桐编程计算其中九头鸟、鸡和兔子各有多少只,你能帮助桐桐吗?
输入:
没有输入啦~
输出:
前面若干行,每行输出满足题目条件的一个解,共三个数,分别表示九头鸟、鸡和兔子的只数,最后一行输出题目解的总数。
鸡兔同笼升级版,要是小学会编程,就不会被这玩意摧残了。。。最基础做法:3个for循环。

#include <stdio.h>
#define N 1000
int main()
{
    int x,y,z,i=0;
    for(x=0;x<=11;x++)
    {
        for(y=0;y<=50;y++)
        {
            for(z=0;z<=25;z++)
            {
                if((9*x+y+z==100)&&(x+y+2*z==50))
                {
                    printf("%d %d %d\n",x,y,z);
                    i++;
                }
            }
        }
    }
    printf("%d\n",i);
    return 0;
}

【枚举】桐桐去购物

题目描述:
桐桐周末陪妈妈到市场购物。她和妈妈来到一个买鸡的摊位,发现鸡的价格有三种:公鸡每只5元钱,母鸡每只3元钱,小鸡3只1元钱。妈妈就给桐桐出了一道计算题:如果用n元钱买m只鸡,问公鸡、母鸡和小鸡可以各买多少只?注意:必须把n元钱正好用完,且买的各种鸡的只数为大于等于0的整数。桐桐回到家里便拿起笔来认真计算,算了好久还没得出答案。聪明的你通过编写程序帮助桐桐找出结果好吗?
输入:
只有1行,两个数n和m 0<n,m≤20000。
输出:
有若干行,每行有三个数,分别为公鸡、母鸡和小鸡的只数,用空格隔开,按照公鸡只数升序排列。
贼基础的题,但是总会谜之超时,TLE了几次之后,又谜之AC。。。

#pragma GCC optimize("Ofast","inline","-ffast-math")
#pragma GCC target("avx,sse2,sse3,sse4,mmx")
#pragma GCC optimize(2)
#include<bits/stdc++.h>
using namespace std;
int main()
{
    double n=0;
    double m=0;
    cin>>n>>m;
    double i,j;
    if(n>0&&m<=20000)
    {
        for(i=0; i<n/5; i++)
        {
            for(j=0; j<m; j++)
            {
                double k=m-i-j;
                if(5*i+3*j+k/3==n)
                {
                    cout<<i<<" "<<j<<" "<<k<<endl;
                }
            }
        }
    }
    return 0;
}

【枚举】打印算式

题目描述:
设有下列的算式:
在这里插入图片描述
求出□中的数字,并打印出完整的算式来。
输出:
除数靠当前行的最左边,横线的长度与被除数的长度相同,被除数、除数与“)”之间没有空格。
注意格式,然后,就没了。

#include<bits/stdc++.h>
using namespace std;
int main()
{
    int a,b,c,d,e;
    for (a=10; a<13; a++)
    {
        c = 8*a;
        d = 9*a+1;
        e = 9*a;
        b = 100*c+d;
        if (b>=1000 && b<10000 && c<100 && e>=100 && e<1000)
        {
            printf("    809\n");
            printf("   ----\n");
            printf("%d)%d\n",a,b);
            printf("   %d\n",c);
            printf("   ----\n");
            printf("    %d\n",d);
            printf("    %d\n",e);
            printf("   ----\n");
            printf("      1\n");
        }
    }
    return 0;
}

【枚举】ISBN码

题目描述:
Farmer John的奶牛们喜欢看书,并且Farmer John发现在他的奶牛们稍微看了些有关于自然科学的书时,会产出更多的牛奶。他决定更新牛棚里的图书馆,把原廉价的小说换成算术和数学的课本。不幸的是,有些新书掉到了泥浆里面,现在它们的ISBN号码很难分辨出来了。
ISBN(国际标准图书编号)是由十个阿拉伯数字组成的编码,用来唯一地标识一本书。前九个阿拉伯数字描述这本书的一些信息,最后一个数字用来验证ISBN码是否正确。要验证ISBN码的正确性,你要把第一个数字乘以十,把第二个数字乘以九,把第三个数字乘以八……直到最后一个数字乘上一,再把这些积累加起来,如果所得的和可以被11整除的话,那么这就是一个合法的ISBN码。比如说0201103311是一个合法的ISBN,因为
10×0+9×2+8×0+7×t+6×1+5×0+4×3+3×3+2×1+1×1=55
前九个数字都在0到9之间。有时候,最后一个数字需要取到10,那么我们就把最后一个数字写成大写X(这时就不叫数字了,呵呵),比如156881111X也是一个合法的ISBN码。你的任务就是在给你丢失了一个数字的ISBN码之后,确定那个丢失的数字。丢失数字的地方用“?”表示。
输入:
一个十个数字组成的ISBN码,其中包含用“?”表示的一个丢失的数字。
输出:
就是那个丢失的数码(0~9或大写X)。如果标有“?”的位置上没有数字可以使之成为一个合法的ISBN码的话,就输出-l。
样例输入
02011?3311
样例输出:
0
这种只有一组输入的,最好输出完直接return 0,要不然容易谜之WA。

#include<bits/stdc++.h>
using namespace std;
char a[15];
int main()
{
    scanf("%s", a);
    int ans = 0, v = 0;
    for (int i = 0; i < 10; i++)
    {
        if(a[i] == 'X')
        {
            ans =ans+ 10;
            continue;
        }
        if(a[i] == '?')
            v = i;
        else
            ans =ans+(10 - i) * (a[i] - '0');
    }
    if(ans == 0)
    {
        printf("-1\n");
        return 0;
    }
    int u = 0;
    for (int i = 0; i < 10; i++)
    {
        if((ans + i * (10 - v)) % 11 == 0)
        {
            printf("%d\n", i);
            u = 1;
            break;
        }
    }
    if(u==0)
    {
        if((ans + 10) % 11 == 0 &&v == 9)
        {
            printf("X\n");
        }
        else
        {
            printf("-1\n");
        }
        return 0;
    }
    return 0;
}

【枚举】格子位置

题目描述:
输入三个自然数N,i,j(l≤i≤N,1≤j≤N),输出在一个N×N格的棋盘中,与格子(i,j)同行、同列、同一对角线的所有格子的位置。例如,n=4,i=2,j=3表示棋盘中的第二行第三列的格子,如:n=4,i=2,j=3表示了棋盘中的第二行第三列的格子,如下图:
在这里插入图片描述
当n=4,i=2,j=3时,输出的结果是:
(2,1) (2,2) (2,3) (2,4) {同一行上格子的位置}
(1,3) (2,3) (3,3) (4,3) {同列列上格子的位置}
(1,2) (2,3) (3,4) {左上到右下对角线上的格子的位置}
(4,1) (3,2) (2,3) (1,4) {左下到右上对角线上的格子的位置}
输入:
只有1行,共3个数,分别为N(1≤N≤10000),i,j的值。
输出:
按照题目描述的格式输出。
样例输入:
4 2 3
样例输出:
(2,1)(2,2)(2,3)(2,4)
(1,3)(2,3)(3,3)(4,3)
(1,2)(2,3)(3,4)
(4,1)(3,2)(2,3)(1,4)
暴力求解,不会的面壁。

#pragma GCC optimize("Ofast","inline","-ffast-math")
#pragma GCC target("avx,sse2,sse3,sse4,mmx")
#pragma GCC optimize(2)
#include<bits/stdc++.h>
using namespace std;
int main()
{
    int n,i,j;
    scanf("%d%d%d",&n,&i,&j);
    for(int ii=1;ii<=n;ii++)
    {
        printf("(%d,%d)",i,ii);
    }
    printf("\n");
    for(int ii=1;ii<=n;ii++)
    {
        printf("(%d,%d)",ii,j);
    }
    printf("\n");
    int u=i,v=j;
    while(u&&v)
    {
        u=u-1;
        v=v-1;
    }
    u++;
    v++;
    while(u<=n&&v<=n)
    {
        printf("(%d,%d)",u,v);
        u++;
        v++;
    }
    printf("\n");
    u=i,v=j;
    while(u<=n&&v)
    {
        u=u+1;
        v=v-1;
    }
    u--,v++;
    while(u&&v<=n)
    {
        printf("(%d,%d)",u,v);
        u--,v++;
    }
    printf("\n");
    return 0;
}

【枚举】勾股数

题目描述:
输入整数R,输出小于等于R的满足X2+Y2=Z2的所有正整数X,Y,Z。
输入:
只有一个数:R(5≤R≤1024)。
输出:
只有一个数:表示共有多少组满足条件的勾股数。
打表也行,但没必要,直接三个for搞定。

#include <bits/stdc++.h>
using namespace std;
int main()
{
    int n,ans=0;
    scanf("%d",&n);
    for(int i=1;i<=1024;i++)
    {
        for(int j=i+1;j<=1024;j++)
        {
            for(int k=j+1;k<=1024;k++)
            {
                if(i*i+j*j==k*k&&k<=n)
                {
                    ans++;
                }
            }
        }
    }
    printf("%d\n",ans);
    return 0;
}

【枚举】桐桐的数学难题

题目描述:
今天数学课上,桐桐学习了质数的知识:一个正整数如果只能被1和它本身整除,那么这个整数便是质数。桐桐就想:任意一个正整数是否都能分解成若干个质数相乘的形式呢?输入一个正整数n,把它分解成质因子相乘的形式,如果为质数则输出该数本身。如:36=2×2×3×3;19=19。你能帮助桐桐解决这个难题吗?
输入:
输入一个正整数n(2≤n≤1e9)
输出:
把它分解成质因子相乘的形式,如果为质数则输出该数本身,乘数从小到大输出。
样例输入:
99
样例输出:
99=3311
这个蛮有意思的,说一下。需要求素数,我们有两种选择,欧拉筛和米勒罗宾素数定理,欧拉筛比较慢,但是准确,米勒罗宾快,但会有出错率。由于1e9的数据,欧拉筛打不出来,所以博主采取了两者并进的方式,大数用米勒罗宾,小数用欧拉筛,然后答案用STL里的队列(queue,先进先出)存起来,最后再一个一个往出压。

#include <bits/stdc++.h>
typedef long long ll;
using namespace std;
//欧拉筛,v[n]为0,则n为素数
int a[1000005],v[1000005];
void getprime()
{
    int m=0;
    for(int i=2; i<=1000000; i++)
    {
        a[m++]=i;
        for(int j=0; j<=m&&a[j]*i<=1000000; j++)
        {
            v[i*a[j]]=1;
            if(i%a[j]==0)
                break;
        }
    }
}
//米勒罗宾,返回值为1则为素数
ll prime[6] = {2, 3, 5, 233, 331};
ll qmul(ll x, ll y, ll mod)
{
    return (x * y - (long long)(x / (long double)mod * y + 1e-3) *mod + mod) % mod;
}
ll qpow(ll a, ll n, ll mod)
{
    ll ret = 1;
    while(n)
    {
        if(n & 1)
            ret = qmul(ret, a, mod);
        a = qmul(a, a, mod);
        n >>= 1;
    }
    return ret;
}
bool Miller_Rabin(ll p)
{
    if(p < 2)
        return 0;
    if(p != 2 && p % 2 == 0)
        return 0;
    ll s = p - 1;
    while(! (s & 1))
        s >>= 1;
    for(int i = 0; i < 5; ++i)
    {
        if(p == prime[i])
            return 1;
        ll t = s, m = qpow(prime[i], s, p);
        while(t != p - 1 && m != 1 && m != p - 1)
        {
            m = qmul(m, m, p);
            t <<= 1;
        }
        if(m != p - 1 && !(t & 1))
            return 0;
    }
    return 1;
}
int main()
{
    ll n;
    scanf("%lld",&n);
    if(Miller_Rabin(n))
    {
        printf("%lld=%lld\n",n,n);
    }
    else
    {
        queue<ll>que;
        ll m=n;
        while(!Miller_Rabin(n))
        {
            for(ll i=2; i<=n; i++)
            {
                if(v[i]==0&&n%i==0)
                {
                    que.push(i);
                    n=n/i;
                    break;
                }
            }
        }
        printf("%lld=",m);
        while(!que.empty())
        {
            ll top=que.front();
            que.pop();
            printf("%lld*",top);
        }
        printf("%lld\n",n);
    }
    return 0;
}

【枚举】因子个数

题目描述:
桐桐做完数学作业,闲来无事,她发现整数N的因子很有趣,好像还存在一些规律。她想把给定的整数N的因子个数计算出来,聪明的你能帮助她吗?
输入:
一个整数N(1≤N≤2000000000)。
输出:
一个整数N的因子个数。
样例输入:
6
样例输出:
4
提示:
样例说明:1、2、3、6共4个因子。
这个题就不挣扎了,直接米勒罗宾,暴力枚举,从2到根号n,能除尽就+1。

#include <bits/stdc++.h>
typedef long long ll;
using namespace std;
ll prime[6] = {2, 3, 5, 233, 331};
ll qmul(ll x, ll y, ll mod)
{
    return (x * y - (long long)(x / (long double)mod * y + 1e-3) *mod + mod) % mod;
}
ll qpow(ll a, ll n, ll mod)
{
    ll ret = 1;
    while(n)
    {
        if(n & 1)
            ret = qmul(ret, a, mod);
        a = qmul(a, a, mod);
        n >>= 1;
    }
    return ret;
}
bool Miller_Rabin(ll p)
{
    if(p < 2)
        return 0;
    if(p != 2 && p % 2 == 0)
        return 0;
    ll s = p - 1;
    while(! (s & 1))
        s >>= 1;
    for(int i = 0; i < 5; ++i)
    {
        if(p == prime[i])
            return 1;
        ll t = s, m = qpow(prime[i], s, p);
        while(t != p - 1 && m != 1 && m != p - 1)
        {
            m = qmul(m, m, p);
            t <<= 1;
        }
        if(m != p - 1 && !(t & 1))
            return 0;
    }
    return 1;
}
int main()
{
    ll n;
    scanf("%lld",&n);
    int ans=2;
    if(Miller_Rabin(n))
    {
        printf("%d\n",ans);
    }
    else if(n==1)
    {
        printf("1\n");
    }
    else
    {
        ans=0;
        int u=sqrt(n);
        for(int i=2;i<=u;i++)
        {
            if(n%i==0)
            {
                ans++;
            }
        }
        ans=ans*2+2;
        if(u*u==n)
            ans--;
        printf("%d\n",ans);
    }
    return 0;
}

【枚举】k个数乘

题目描述:
桐桐想把一个自然数N分解成K个大于l的自然数相乘的形式,要求这K个数按从小到大排列,而且除了第K个数之外,前面(K-l)个数是N分解出来的最小自然数。例如:N=24,K=2时,输出为24=2×12,而不是24=4×6;如N=3,K=I时,3=3; N=3,K=2时,输出则为“No answer!”。你能帮助她吗?
输入:
第1行:N(2≤N≤107);
第2行:K(1≤K≤100)。
输出:
输出样例格式的分解式。
样例输入:
24
2
样例输出:
24=2*12
这题有个深渊巨坑,害我WA了好多发。。。除完之后要判断最后一个数是不是1,如果是,还是要输出“No answer!”的。

#include <bits/stdc++.h>
typedef long long ll;
using namespace std;
int a[5000005],v[5000005];
void getprime()
{
    int m=0;
    for(int i=2; i<=5000000; i++)
    {
        a[m++]=i;
        for(int j=0; j<=m&&a[j]*i<=5000000; j++)
        {
            v[i*a[j]]=1;
            if(i%a[j]==0)
                break;
        }
    }
}
ll prime[6] = {2, 3, 5, 233, 331};
ll qmul(ll x, ll y, ll mod)
{
    return (x * y - (long long)(x / (long double)mod * y + 1e-3) *mod + mod) % mod;
}
ll qpow(ll a, ll n, ll mod)
{
    ll ret = 1;
    while(n)
    {
        if(n & 1)
            ret = qmul(ret, a, mod);
        a = qmul(a, a, mod);
        n >>= 1;
    }
    return ret;
}
bool Miller_Rabin(ll p)
{
    if(p < 2)
        return 0;
    if(p != 2 && p % 2 == 0)
        return 0;
    ll s = p - 1;
    while(! (s & 1))
        s >>= 1;
    for(int i = 0; i < 5; ++i)
    {
        if(p == prime[i])
            return 1;
        ll t = s, m = qpow(prime[i], s, p);
        while(t != p - 1 && m != 1 && m != p - 1)
        {
            m = qmul(m, m, p);
            t <<= 1;
        }
        if(m != p - 1 && !(t & 1))
            return 0;
    }
    return 1;
}
int main()
{
    getprime();
    ll n;
    scanf("%lld",&n);
    int k;
    scanf("%d",&k);
    if(k==1)
    {
        printf("%lld=%lld\n",n,n);
    }
    else
    {
        ll m=n;
        queue<ll>que;
        if(Miller_Rabin(n))
            printf("No answer!\n");
        else
        {
            int flag=0;
            for(int i=2;i<n;i++)
            {
                while(v[i]==0&&n%i==0)
                {
                    int u=que.size();
                    if(u==k-1)
                    {
                        flag=1;
                        break;
                    }
                    que.push(i);
                    n=n/i;
                }
                if(flag==1)
                    break;
            }
            if(que.size()<k-1||n==1)//就是这里啦
                printf("No answer!\n");
            else
            {
                printf("%lld=",m);
                while(!que.empty())
                {
                    ll top=que.front();
                    printf("%lld*",top);
                    que.pop();
                }
                printf("%lld\n",n);
            }
        }
    }
    return 0;
}

【因子游戏】因子游戏

题目描述:
桐桐把一个自然数N的正因子个数记为F(N),例如18的所有正因子为1、2、3、6、9、18,所以F(18)=6。现在给出K,桐桐想求出所有满足F(N)=K的N中最小的数,你能帮助她吗?
输入:
第1行为K,其中0<K≤80。
输出:
如果存在不大于20000的解,则输出这个N,并输出相应的K个因子(行尾有一个 空格);否则输出“NO SOLUTION”。
样例输入:
9
样例输出:
36
1 2 3 4 6 9 12 18 36
重点:数据<20000,此时不暴力,待何时?(注意下1和2的特判)

#include <bits/stdc++.h>
typedef long long ll;
using namespace std;
int main()
{
    int n;
    scanf("%d",&n);
    if(n==1)
    {
        printf("1\n");
        printf("1\n");
    }
    else if(n==2)
    {
        printf("2\n");
        printf("1 2\n");
    }
    else
    {
        int flag=0,cnt=0;
        for(int i=2; i<=20000; i++)
        {
            int ans=2;
            for(int j=2; j<=i/2; j++)
            {
                if(i%j==0)
                {
                    ans++;
                }
            }
            if(ans==n)
            {
                flag=1;
                cnt=i;
                break;
            }
        }
        if(flag==0)
        {
            printf("NO SOLUTION\n");
        }
        else
        {
            printf("%d\n",cnt);
            printf("1 ");
            for(int j=2; j<=cnt/2; j++)
            {
                if(cnt%j==0)
                {
                    printf("%d ",j);
                }
            }
            printf("%d\n",cnt);
        }
    }
    return 0;
}

【枚举】素数的秘密

题目描述:
桐桐在上节分解质因数之后,对素数(质数)发生了兴趣。大家都知道素数就是指只能被l和自身整除的数l例如2,3,5,7就是素数。桐桐想把不大于N的所有素数都输出,你能帮助她解决这个问题吗?
输入:
一个正整数N(1<N≤40000)。
输出:
输出不大于N的所有素数,每行输出5个素数。
样例输入:
2
样例输出:
2
数据小,欧拉筛即可,注意输出格式。

#include <bits/stdc++.h>
typedef long long ll;
using namespace std;
int a[40005],v[40005];
void getprime()
{
    int m=0;
    for(int i=2;i<=40000;i++)
    {
        a[m++]=i;
        for(int j=0;j<=m&&a[j]*i<=40000;j++)
        {
            v[a[j]*i]=1;
            if(i%a[j]==0)
                break;
        }
    }
}
int main()
{
    getprime();
    int n;
    cin>>n;
    int k=1;
    int u=0;
    for(int i=n;i>=2;i--)
    {
        if(v[i]==0)
        {
            u=i;
            break;
        }
    }
    for(int i=2;i<=n;i++)
    {
        if(v[i]==0)
        {
            if(k==5)
            {
                printf("%d\n",i);
                k=1;
            }
            else
            {
                if(u==i)
                    printf("%d\n",i);
                else
                    printf("%d ",i);
                k++;
            }
        }
    }
    return 0;
}

【枚举】找数游戏

题目描述:
一个三位数,各位数字互不相同,十位数字比个位、百位数字之和还要大,且十位、百位数字之和不是质数。桐桐想把符合上述条件的三位数找出来,你能帮助她吗?
输入:

输出:
按照从小到大的顺序,每行输出8个满足条件的三位数,数与数之间有一个空格。
没啥说的啊,还是欧拉筛暴力跑。

#include <bits/stdc++.h>
typedef long long ll;
using namespace std;
int a[40005],v[40005];
void getprime()
{
    int m=0;
    for(int i=2;i<=40000;i++)
    {
        a[m++]=i;
        for(int j=0;j<=m&&a[j]*i<=40000;j++)
        {
            v[a[j]*i]=1;
            if(i%a[j]==0)
                break;
        }
    }
}
int main()
{
    queue<int>que;
    getprime();
    for(int i=1;i<=9;i++)
    {
        for(int j=0;j<=9;j++)
        {
            for(int k=0;k<=9;k++)
            {
                if(j>i+k&&v[i+j]==1&&i!=j&&i!=k&&j!=k)
                {
                    int t=100*i+10*j+k;
                    que.push(t);
                }
            }
        }
    }
    int u=que.back();
    int k=1;
    while(!que.empty())
    {
        if(k==8)
        {
            int p=que.front();
            que.pop();
            printf("%d\n",p);
            k=1;
        }
        else
        {
            int p=que.front();
            que.pop();
            if(u==p)
            {
                printf("%d\n",p);
            }
            else
                printf("%d ",p);
            k++;
        }
    }
    return 0;
}

【枚举】桐桐数

题目描述:
桐桐很喜欢研究数字,特别喜欢研究质数。一天,桐桐发现有一些数字可以表示成两个质数相乘的形式,比如,10=2×5,2,5都是质数,所以10是一个“桐桐数”。所以桐桐决定考考你,她告诉你一个数n,请你判断n是不是“桐桐数”。
输入一个数n(1≤n≤2^31-1)。
输出输出一行,如果n是一个“桐桐数”,则输出“It’s a Tongtong number.”,否则输出“It’s not a Tongtong number.”
样例输入:
10
样例输出:
It’s a Tongtong number.
2^31-1正好是int的边界,所以欧拉筛是没那么大的,后面的枚举也是暴力,不过到n/2就可以停了,毕竟再大没意义。

#include <bits/stdc++.h>
typedef long long ll;
using namespace std;
ll prime[6] = {2, 3, 5, 233, 331};
ll qmul(ll x, ll y, ll mod)
{
    return (x * y - (long long)(x / (long double)mod * y + 1e-3) *mod + mod) % mod;
}
ll qpow(ll a, ll n, ll mod)
{
    ll ret = 1;
    while(n)
    {
        if(n & 1)
            ret = qmul(ret, a, mod);
        a = qmul(a, a, mod);
        n >>= 1;
    }
    return ret;
}
bool Miller_Rabin(ll p)
{
    if(p < 2)
        return 0;
    if(p != 2 && p % 2 == 0)
        return 0;
    ll s = p - 1;
    while(! (s & 1))
        s >>= 1;
    for(int i = 0; i < 5; ++i)
    {
        if(p == prime[i])
            return 1;
        ll t = s, m = qpow(prime[i], s, p);
        while(t != p - 1 && m != 1 && m != p - 1)
        {
            m = qmul(m, m, p);
            t <<= 1;
        }
        if(m != p - 1 && !(t & 1))
            return 0;
    }
    return 1;
}
int main()
{
    getprime();
    int n;
    scanf("%d",&n);
    int flag=0;
    for(int i=2;i<n/2;i++)
    {
        int j;
        if(n%i==0)
        {
            j=n/i;
            if(Miller_Rabin(i)&&Miller_Rabin(j))
            {
                flag=1;
                break;
            }
        }
    }
    if(flag==1)
    {
        printf("It's a Tongtong number.\n");
    }
    else
        printf("It's not a Tongtong number.\n");
    return 0;
}

【枚举】阶乘因子

题目描述:
桐桐刚刚学习了自然数N的阶乘:阶乘(N!)被定义成从1到N的所有整数的乘积,例如5!=5×4×3×2×1=120。随着数N的增大,N!增长得非常快,5!=120,10!=3628800。桐桐想到了一种方法来列举那么大的数:不是直接列出该数,而是按照顺序列举出该数中各个质数因子出现的次数。如825可描述为(01201),意思是对825分解质因数,这些质数因子中有0个2,1个3,2个5,0个7,1个11。请你编一个程序,读入N值,帮助桐桐按顺序输出N!所包含的质数因子的个数。
输入:
只包含1个数N(2≤N≤100000)。
输出:
一个N!中所包含的质数因子的个数(从最小的质数开始)的序列,数与数之间用一个空格隔开。(注意:此题最后不需要输出多余的回车和空格)
样例输入:
53
样例输出:
49 23 12 8 4 4 3 2 2 1 1 1 1 1 1 1
注意是阶乘的因子。

#include <bits/stdc++.h>
typedef long long ll;
using namespace std;
#pragma GCC optimize("Ofast","inline","-ffast-math")
#pragma GCC target("avx,sse2,sse3,sse4,mmx")
#pragma GCC optimize(2)
int prime[100100],ct=0,flag[100100];
int x;
int main()
{
    for(int i=2; i<=100000; i++)
    {
        if(!flag[i])
            prime[ct++]=i;
        for(int j=0; j<ct&&prime[j]*i<=100000; j++)
        {
            flag[prime[j]*i]=1;
            if(i%prime[j]==0)
                break;
        }
    }
    scanf("%d",&x);
    int fg=1;
    for(int j=0; j<ct&&prime[j]<=x; j++)
    {
        int xz=prime[j];
        int ans=0;
        while(1)
        {
            if(x/xz!=0)
                ans+=x/xz;
            else
                break;
            xz=xz*prime[j];
        }
        if(fg==0)
            printf(" ");
        else
            fg=0;
        printf("%d",ans);
    }
    return 0;
}

【枚举】桐桐的思考

题目描述:
桐桐在学完了上节课的知识后,对信息学越发感兴趣了。桐桐是一个很善于思考的学生,她发现上节课中例题的n最大是40000,如果数据再大一些,比如n=10^6,那么判断素数的算法能否在1秒内给出答案呢?桐桐用程序实际测试的时间超过了1秒,你能帮助桐桐解决这个难题吗?即:在1秒的时间内输出不大于n (l
输入:
一个正整数n(1<n≤106)。
输出“
输出不大于n的所有素数,每行输出5个素数。
样例输入:
100
样例输出:
2 3 5 7 11
13 17 19 23 29
31 37 41 43 47
53 59 61 67 71
73 79 83 89 97
嘿嘿,看来我的算法还是不错的,上一个那个数据为40000的题的代码,我改了个数据,交上来还是AC。

#include <bits/stdc++.h>
typedef long long ll;
using namespace std;
int a[1000005],v[1000005];
void getprime()
{
    int m=0;
    for(int i=2;i<=1000000;i++)
    {
        a[m++]=i;
        for(int j=0;j<=m&&a[j]*i<=1000000;j++)
        {
            v[a[j]*i]=1;
            if(i%a[j]==0)
                break;
        }
    }
}
int main()
{
    getprime();
    int n;
    cin>>n;
    int k=1;
    int u=0;
    for(int i=n;i>=2;i--)
    {
        if(v[i]==0)
        {
            u=i;
            break;
        }
    }
    for(int i=2;i<=n;i++)
    {
        if(v[i]==0)
        {
            if(k==5)
            {
                printf("%d\n",i);
                k=1;
            }
            else
            {
                if(u==i)
                    printf("%d\n",i);
                else
                    printf("%d ",i);
                k++;
            }
        }
    }
    return 0;
}

【枚举】孪生素数

题目描述:
桐桐把大小之差不超过2的两个素数称为一对孪生素数,如2和3、3和5、17和19等等。请你帮助桐桐统计一下,在不大于自然数N的素数中,孪生素数的对数。
输入:
一个自然数N(N≤10^6)。
输出:
一个整数,表示N以内孪生素数的对数。
样例输入:
20
样例输出:
5
暴力枚举。。。这题有点坑,百科上说相差为2的叫孪生素数,这题说不超过2就行,幸亏有样例,要不然估计是要WA一次。

#include <bits/stdc++.h>
typedef long long ll;
using namespace std;
int a[1000005],v[1000005];
void getprime()
{
    int m=0;
    for(int i=2;i<=1000000;i++)
    {
        a[m++]=i;
        for(int j=0;j<=m&&a[j]*i<=1000000;j++)
        {
            v[a[j]*i]=1;
            if(i%a[j]==0)
                break;
        }
    }
}
int main()
{
    getprime();
    int n;
    cin>>n;
    int ans=0;
    for(int i=3;i<=n;i++)
    {
        if((v[i]==0&&v[i-2]==0)||(v[i]==0&&v[i-1]==0))
            ans++;
    }
    printf("%d\n",ans);
    return 0;
}

【枚举】桐桐的猜想

题目描述:
今天,桐桐在复习素数的知识时,发现了有趣的现象,例如4=2+2,5=2+3,6=3+3,7=2+5等等,桐桐列举了很多数,都是这样,所以她大胆地得出了一个结论:任何一个不小于4的数都能表示成两个质数的和。你能找出一些反例,证明桐桐的结论是错误的吗?
输入:
第1行为一个整数n(1≤n≤50);
接下来有n行,每行包含一个整数m (3≤m≤10^6)。
输出:
共n行,每行对应于每一个m,如果m不能表示成两个质数的和,则输出“NO WAY!”;否则输出一种方案。如果有多种可行方案,输出两个质数的差最大的那一种。
样例输入:
2
10
11
样例输出:
10=3+7
NO WAY!
枚举到n/2,再不行就是没有。

#include <bits/stdc++.h>
typedef long long ll;
using namespace std;
int a[3000005],v[3000005];
void getprime()
{
    int m=0;
    for(int i=2; i<=3000000; i++)
    {
        a[m++]=i;
        for(int j=0; j<=m&&a[j]*i<=3000000; j++)
        {
            v[a[j]*i]=1;
            if(i%a[j]==0)
                break;
        }
    }
}
int main()
{
    getprime();
    int t;
    scanf("%d",&t);
    while(t--)
    {
        int n;
        int flag=0;
        scanf("%d",&n);
        for(int i=2; i<=n/2; i++)
        {
            int j=n-i;
            if(v[i]==0&&v[j]==0)
            {
                printf("%d=%d+%d\n",n,i,j);
                flag=1;
                break;
            }
        }
        if(flag==0)
            printf("NO WAY!\n");
    }
    return 0;
}

【枚举】统计素数

题目描述:
桐桐想统计某个区间范围里的素数,例如,A=2,B=10,则A和B之间(包括A、B)素数一共有4个,分别为:2,3,5,7。现在桐桐给出N个区间范围,问每个区间有多少个素数。请你帮助她统计一下。
输入:
第1行一个整数/N(1≤N≤10^5);
后有N行,每行两个整数A B(1≤A≤B≤10^6),用空格隔开,表示一个区间范围。
输出:
共N行,每行一个整数,对应区间范围的素数个数。
样例输入:
2
2 8
1 13
样例输出:
4
6
一个区间,这种题用线段树妥妥的没问题(线段树要开4倍空间)。简单介绍一下线段树,线段树是一种二叉树,它的每一个节点代表一个区间[a,b],它的叶节点代表单位区间[a,a],即点a。
对一个非叶节点,设它的编号为x,区间为[a,b],那么它的左儿子的编号就是(2x),区间是[a,(a+b)/2];它的右儿子的编号是(2x+1),区间是[(a+b)/2+1,b]。
下面的build函数是建树,l为左端点,r为右端点,rt一般在主函数里取1;update函数是更新(p点+v);query函数是询问,l1到r1的sum值,rt一般在主函数里取1。

#include <bits/stdc++.h>
typedef long long ll;
using namespace std;
int a[4000005],v[4000005];
void getprime()
{
    int m=0;
    for(int i=2; i<=4000000; i++)
    {
        a[m++]=i;
        for(int j=0; j<=m&&a[j]*i<=4000000; j++)
        {
            v[a[j]*i]=1;
            if(i%a[j]==0)
                break;
        }
    }
}
int sum[4000005];
//下面是线段树模板
void build(int l,int r,int rt)
{
    if(r==l)
    {
        if(l==1)
            sum[rt]=0;//1要特判
        else if(v[l]==0)
            sum[rt]=1;//是素数
        else
            sum[rt]=0;//不是素数
        return;
    }
    int mid=(l+r)/2;
    build(l,mid,rt*2);
    build(mid+1,r,rt*2+1);
    sum[rt]=sum[rt*2]+sum[rt*2+1];
}
void update(int p,int v,int l,int r,int rt)
{
    if(r==l)
    {
        sum[rt]+=v;
        return;
    }
    int mid=(l+r)/2;
    if(p<=mid)
        update(p,v,l,mid,rt*2);
    else
        update(p,v,mid+1,r,rt*2+1);
    sum[rt]=sum[rt*2]+sum[rt*2+1];
}
int query(int l1, int r1, int l, int r, int rt)
{
    if(l1 <= l && r <= r1)
        return sum[rt];
    int mid = (l + r) / 2;
    int ret = 0;
    if (l1 <= mid)
        ret += query(l1, r1, l, mid,rt * 2);
    if (r1 > mid)
        ret += query(l1, r1, mid + 1, r, rt * 2 + 1);
    return ret;
}
int main()
{
    getprime();
    build(1,1000000,1);
    int t;
    scanf("%d",&t);
    while(t--)
    {
        int a,b;
        scanf("%d%d",&a,&b);
        int u=query(a,b,1,1000000,1);
        printf("%d\n",u);
    }
    return 0;
}

【枚举】桐桐的研究

题目描述:
在第一节桐桐已经接触过因数(子),其实也就是约数:对于一个自然数n,如果存在一个非0的正整数d(d≤n),使得n mod d=0,则d是n的约数。n=l时,约数只有一个为1,当n>l时,要分两种情况:若n为质数,则其约数只有2个,即1和它本身;若n为非质数,则其约数个数肯定大于2个。显然n的最大约数即为它本身。
桐桐对两个自然数n和m的公约数发生了兴趣,例如:n=8,m=36,它们的公约数有:1,2,4,其中最大的那个公约数4称为这两个自然数的最大公约数。
同时,两个自然数n和m的公倍数也引起了桐桐的兴趣:公倍数的概念与公约数类似,例如,n=8,m=36,它们的公倍数有:72,144,216,…,有无限多个,其中72是最小的公倍数,称为这两个自然数的最小公倍数。
请你编写程序帮助桐桐求两个自然数的最大公约数和最小公倍数。
输入:
只有1行,为两个自然数m,n(m≤108,n≤108),用空格隔开。
输出:
共2行,第1行为最大公约数,第2行为最小公倍数。
样例输入:
10 15
样例输出:
5
30
递归的写一下gcd算法,然后,就没了。。。

#include <bits/stdc++.h>
typedef long long ll;
using namespace std;
ll gcd(ll x,ll y)
{
    if(y==0)
        return x;
    else
        return gcd(y,x%y);
}
ll lcm(ll x,ll y)
{
    return x*y/gcd(x,y);
}
int main()
{
    ll n,m;
    cin>>n>>m;
    cout<<gcd(max(n,m),min(n,m))<<endl;
    cout<<lcm(max(n,m),min(n,m))<<endl;
    return 0;
}

【枚举】桐桐的深入研究

题目描述:
两个数的最大公约数与最小公倍数的问题解决了,桐桐又进行了进一步的研究。她发现求n个正整数的最大公约数与最小公倍数要复杂一些,你能帮助她解决这个问题吗?
输入:
第1行一个数n(2≤n≤100),表示一共n个正整数;
第2行有n个正整数,相邻的数用空格隔开,每个数不超过30000。
输出:
第1行一个数,表示n个正整数的最大公约数;
第2行一个数,表示n个正整数的最小公倍数。
答案保证不超过长整型。
样例输入:
3
3 4 5
样例输出:
1
60
从大到小排个序,然后做法同上。

#include <bits/stdc++.h>
typedef long long ll;
using namespace std;
ll gcd(ll x,ll y)
{
    ll a,b;
    a=max(x,y);
    b=min(x,y);
    x=a;
    y=b;
    if(y==0)
        return x;
    else
        return gcd(y,x%y);
}
ll lcm(ll x,ll y)
{
    return x*y/gcd(x,y);
}
bool cmp(ll a,ll b)
{
    return a>b;
}
int main()
{
    ll n;
    ll a[105];
    cin>>n;
    for(int i=1;i<=n;i++)
    {
        scanf("%I64d",&a[i]);
    }
    sort(a+1,a+1+n,cmp);
    int minn=gcd(a[1],a[2]);
    int maxn=lcm(a[1],a[2]);
    for(int i=3;i<=n;i++)
    {
        minn=gcd(minn,a[i]);
        maxn=lcm(maxn,a[i]);
    }
    printf("%d\n",minn);
    printf("%d\n",maxn);
    return 0;
}

【枚举】桐桐的游戏I

题目描述

桐桐正在和同桌吉吉玩一种数字游戏。游戏规则是这样的:给定两个正整数M和N,从桐桐开始,取其中较大的一个数,减去较小的数的正整数倍,当然,得到的数K不能小于0。然后是吉吉对刚才得到的数K和M、N中较小的那个数,再进行同样的操作……直到一个人得到了O,他就取得了胜利。下面是他们用(25,7)两个数游戏的过程。
初始:25 7
桐桐:11 7{18 7,11 7,4 7均可能)
吉吉:4 7
桐桐:4 3
吉吉:1 3
桐桐:1 0
桐桐取得了游戏的胜利。现在,假设他们都能够“完美”地操作,谁会取得胜利呢?
输入:
第1行只有一个数c(1≤C≤1000),表示有C组测试数据;
下面有C行,每行有两个正整数M和N,大小均不超过长整型。
输出:
共有C行,每行输出对当前组数据的游戏结果。如果桐桐胜利,则输出“Tongtong wins”;否则输出“Jiji wins”。
样例输入:
2
25 7
24 15
样例输出:
Tongtong wins
Jiji wins
这明明是个博弈的题,搞不懂为什么放到枚举这。。。还好这博弈不难:大数只要是小数的两倍及以上,那么这个人就具有主动权(可以直接拿到比小数小,也可以到小数的1倍和2倍之间,让下一个人拿的情况固定),每次主动权,num++,最后num是奇数,桐桐赢,否则吉吉赢。

#include <bits/stdc++.h>
typedef long long ll;
using namespace std;
ll minus1(ll a,ll b,ll num)
{
    ll c=max(a,b);
    ll d=min(a,b);
    while(d>0)
    {
        num++;
        if(c/d>1)
            return num;
        else
        {
            ll e=c%d;
            c=d;
            d=e;
        }
    }
    return num;
}
int main()
{
    int t;
    scanf("%d",&t);
    while(t--)
    {
        ll a,b;
        scanf("%I64d%I64d",&a,&b);
        ll num=0;
        num=minus1(a,b,0);
        if(num%2==0)
            printf("Jiji wins\n");
        else
            printf("Tongtong wins\n");
    }
    return 0;
}

【枚举】分数计算器

题目描述:
Victor是一位很著名的科学家,在他的研究工作中经常要进行分数的运算。为了提高工作效率,Victor决定设计一个简易的分数计算器,该计算器能够进行分数的加、减、乘、除运算,并能将结果化为最简分数和带分数。
假设参加运算的分数都不是带分数,并将整数看作分母为1的分数。你能发挥聪明才智,帮助Victor设计出这个分数计算器吗?
(1)分数乘法法则可归结为:
分数乘以分数,用分子相乘的积作分子,分母相乘的积作分母。
在这里插入图片描述
(2)分数除法法则可归结为:
甲数除以乙数(0除外),等于甲数乘以乙数的倒数。例如:
在这里插入图片描述
输入第一行:输入第一个分数的分子和分母。
第二行:输入运算符。
第三行:输入第二个分数的分子和分母。
输出:
以q/p的形式输出运算结果的最简分数;是假分数的还要化为带分数,先输出整数部分,再输出后面部分。
样例输入:
9 1
/
4 11
样例输出:
24 3/4
唯一的问题是约分,用gcd就好了。

#include <bits/stdc++.h>
typedef long long ll;
using namespace std;
int gcd(int a,int b)
{
    if(b==0)
        return a;
    else
        return gcd(b,a%b);
}
int main()
{
    int a,b;
    char ch;
    int c,d;
    cin>>a>>b;
    cin>>ch;
    cin>>c>>d;
    int e,f;
    if(ch=='*')
    {
        e=a*c;
        f=b*d;
    }
    else if(ch=='/')
    {
        e=a*d;
        f=b*c;
    }
    else if(ch=='+')
    {
        e=a*d+b*c;
        f=b*d;
    }
    else
    {
        e=a*d-b*c;
        f=b*d;
    }
    int u=gcd(max(e,f),min(e,f));
    e/=u;
    f/=u;
    int r=e/f;
    int yu=e%f;
    if(r>0)
        printf("%d ",r);
    printf("%d/%d\n",yu,f);
    return 0;
}

【枚举】桐桐的砝码

题目描述:
桐桐有2g、3g、5g、7g、10g、15g的砝码各有一枚。她想知道用这些砝码能称出多少种不同的质量。
输出:
只有一个数,表示能称出的不同质量的个数。
这个题看着人畜无害,实际上还是有个坑的,要把0的情况减去。

#include <bits/stdc++.h>
typedef long long ll;
using namespace std;
int v[2000000]={0};
int main()
{
    int cnt=0;
    int a[2]= {0,2};
    int b[2]= {0,3};
    int c[2]= {0,5};
    int d[2]= {0,7};
    int e[2]= {0,10};
    int f[2]= {0,15};
    int num=0;
    for(int i=0; i<=1; i++)
    {
        for(int j=0; j<=1; j++)
        {
            for(int k=0; k<=1; k++)
            {
                for(int s=0; s<=1; s++)
                {
                    for(int g=0; g<=1; g++)
                    {
                        for(int h=0; h<=1; h++)
                        {
                            int ans=a[i]+b[j]+c[k]+d[s]+e[g]+f[h];
                            num++;
                            if(v[ans]==0)
                            {
                                v[ans]=1;
                                cnt++;
                            }
                        }
                    }
                }
            }
        }
    }
    cout<<cnt-1<<endl;
    return 0;
}

【枚举】砝码称重

题目描述:
桐桐有1g、2g、3g、5g、10g、20g的砝码各若干枚(其总质量≤1000)。她想知道用这些砝码能称出多少种不同的质量。
输入:
只有1行:共6个数,分别为al,a2,a3,a4,a5,a6,表示1g砝码有a1个,2g砝码有a2个,...,20g砝码有a6个,每种砝码数量不超过10个。
输出:
只有一个数:N,表示用这些砝码能称出的不同质量的个数,但不包括一个砝码也不用的情况。
样例输入:
1 1 0 0 0 0
样例输出:
3
提示:
表示可以称出1g,2g,3g三种不同的质量。
跟上题做法一样。

#include<bits/stdc++.h>
#define maxn 220
#define INF 0x7f7f7f7f
using namespace std;
int main()
{
    int a1,a2,a3,a4,a5,a6;
    int sum=0;
    int u[1001]={0};
    cin>>a1>>a2>>a3>>a4>>a5>>a6;
    for(int i=0; i<=a1; i++)
    {
        for(int i1=0; i1<=a2; i1++)
        {
            for(int i2=0; i2<=a3; i2++)
            {
                for(int i3=0; i3<=a4; i3++)
                {
                    for(int i4=0; i4<=a5; i4++)
                    {
                        for(int i5=0; i5<=a6; i5++)
                        {
                            int ans=i*1+i1*2+i2*3+i3*5+i4*10+i5*20;
                            if(u[ans]==0)
                            {
                                u[ans]=1;
                                sum++;
                            }
                        }
                    }
                }
            }
        }
    }
    cout<<sum-1<<endl;
    return 0;
}

【枚举】求组合数

题目描述:
桐桐想找出n个自然数(1,2,3,…,n)中r个数的组合。例如,当n=5,r=3时,所有组合为:123 124 125 134 135 145 234 235 245 345,总共有10种组合。
输入:
只有1行:两个数n(1≤n≤30)和r(1≤r≤10)。
输出:
共2行,第1行:满足条件的所有组合,相邻组合间用空格隔开;第2行:满足条件的组合总数。
样例输入:
5 3
样例输出:
123 124 125 134 135 145 234 235 245 345
10
提示:
行末有空格
枚举没想出来咋解,搜索倒是可以,dfs暴力求解即可。

#include <bits/stdc++.h>
#define inf 1000000007
typedef long long ll;
using namespace std;
int n,r,ct=0;
int s[100],flag[100];
void dfs(int lj)
{
    if(lj==r+1)
    {
        for(int i=1; i<=r; i++)
            printf("%d",s[i]);
        printf(" ");
        ct++;
        return;
    }
    for(int i=1; i<=n; i++)
    {
        if(flag[i]||i<=s[lj-1])
            continue;
        s[lj]=i;
        flag[i]=1;
        dfs(lj+1);
        flag[i]=0;
    }
}
int main()
{
    scanf("%d%d",&n,&r);
    dfs(1);
    printf("\n");
    printf("%d\n",ct);
    return 0;
}

【枚举】灯的开关状态

题目描述:
有N个灯放在一排,从l到N依次顺序编号。有N个人也从1到N依次编号。l号将灯全部关闭,2号将凡是2的倍数的灯打开;3号将凡是3的倍数的灯作相反处理(该灯如为打开的,则将它关闭;如关闭的,则将它打开)。以后的人都和3号一样,将凡是自己编号倍数的灯作相反处理。
编程实现:第N个人操作后,按顺序输出灯的状态(1表示灯打开,0表示灯关闭)。
输入:
N(1≤N≤2000000),灯的个数。
输出:
灯的状态,用01序列表示,中间无空格。
样例输入:
2
样例输出:
01
这题别想多,其实就是一倍一倍的往上加(之前记得有道题还要用唯一分解定理的,不过这个数据小,没必要)。

#include <bits/stdc++.h>
typedef long long ll;
using namespace std;
int s[2000010];
int main()
{
    int n,i,j;
    scanf("%d",&n);
    memset(s,1,sizeof(s));
    for(i=1; i<=n; i++)
        for(j=i; j<=n; j+=i)
            s[j-1]=!s[j-1];
    for(i=0; i<n; i++)
        printf("%d",s[i]);
    printf("\n");
    return 0;
}
  • 6
    点赞
  • 29
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值