Gym 240668 - A/B/C/D/E - (Done)

链接:https://codeforces.com/gym/240668


A - Olesya and Rodion - [水]

题解:注意到 $t$ 的范围是 $[2,10]$,对于位数小于 $2 \times 3 \times \cdots \times 10 = 3628800$ 的数,暴力枚举去找;否则就直接在 $3628800$ 后面补零即可。

AC代码:

#include<bits/stdc++.h>
using namespace std;
int n,t;
int p10[8];
int main()
{
    ios::sync_with_stdio(0);

    cin>>n>>t;
    if(n>=7)
    {
        cout<<3628800;
        for(int i=8;i<=n;i++) cout<<0;
        cout<<endl;
    }
    else
    {
        p10[0]=1;
        for(int i=1;i<8;i++) p10[i]=p10[i-1]*10;

        bool ok=0;
        for(int x=p10[n-1];x<p10[n];x++)
        {
            if(x%t==0)
            {
                cout<<x<<endl;
                ok=1;
                break;
            }
        }
        if(!ok) cout<<-1<<endl;
    }
}

B - Kolya and Tanya - [组合数]

题解:对于一个等边三角形上的三个人,有 $20$ 种方案使得和不等于 $6$,有 $7$ 种方案使得和等于 $6$,然后很容易得到公式 $\sum_{i=1}^{n} C_{n}^{i} \cdot 20^i \cdot 7^{n-i}$。

AC代码:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll mod=1e9+7;
int n;
ll fpow(ll a,ll n)
{
    ll res=1,base=a%mod;
    while(n)
    {
        if(n&1) res*=base, res%=mod;
        base*=base, base%=mod;
        n>>=1;
    }
    return res%mod;
}
ll inv(ll n){return fpow(n,mod-2);}

int main()
{
    ios::sync_with_stdio(0);
    cin.tie(0), cout.tie(0);

    cin>>n;
    ll ans=0;
    ll C=1ll, A=1ll, B=fpow(7ll,n);
    for(int i=1;i<=n;i++)
    {
        C=C*(n+1-i), C%=mod;
        C=C*inv(i), C%=mod;

        A*=20ll, A%=mod;
        B*=inv(7), B%=mod;

        ans+=((C*A)%mod)*B%mod, ans%=mod;
    }
    cout<<ans<<endl;
}

C - Marina and Vasya - [字符串]

题解:

要有 $t$ 个不同字符,就是要有 $n-t$ 个相同字符;对于 $s_1,s_2$ 两个字符串,如果存在 $s_1[i] = s_2[i]$ 就尽量让 $s_3[i]$ 也是这个字符。如果直接就能把 $n-t$ 个要求相同的字符全搞定了,剩下的就可以乱放。

如果还剩下来 $n-t-same$(此处 $same$ 代表 $s_1,s_2$ 中相同位置且相同字符的数目),要求有这么多个相同字符。那记 $diff$ 代表 $s_1,s_2$ 中相同位置但不同字符的数目,讨论一下 $2(n-t-same)$ 与 $diff$ 的关系即可。

AC代码:

#include<bits/stdc++.h>
using namespace std;
const int maxn=1e5+5;
int n,t;
string s1,s2,s3;
bool f[maxn];
int same,diff;
inline char Find(char x,char y)
{
    if(x!=‘a‘ && y!=‘a‘) return ‘a‘;
    if(x!=‘b‘ && y!=‘b‘) return ‘b‘;
    if(x!=‘c‘ && y!=‘c‘) return ‘c‘;
}
int main()
{
    ios::sync_with_stdio(0);
    cin.tie(0), cout.tie(0);

    cin>>n>>t; t=n-t;
    cin>>s1>>s2;

    for(int i=0;i<n;i++) s3+=‘0‘;

    int diff=0;
    for(int i=0;i<n;i++)
    {
        if(s1[i]!=s2[i]) diff++;
        if(s1[i]==s2[i] && t>0)
        {
            s3[i]=s1[i];
            t--;
        }
    }

    if(t>0)
    {
        if(2*t>diff) s3="-1";
        else
        {
            int cnt=0;
            for(int i=0;i<n;i++)
            {
                if(s3[i]!=‘0‘) continue;
                s3[i]=s1[i], cnt++;
                if(cnt==t) break;
            }
            cnt=0;
            for(int i=0;i<n;i++)
            {
                if(s3[i]!=‘0‘) continue;
                s3[i]=s2[i], cnt++;
                if(cnt==t) break;
            }

            for(int i=0;i<n;i++)
            {
                if(s3[i]!=‘0‘) continue;
                s3[i]=Find(s1[i],s2[i]);
            }
        }
    }
    else
    {
        for(int i=0;i<n;i++)
        {
            if(s3[i]!=‘0‘) continue;
            s3[i]=Find(s1[i],s2[i]);
        }
    }

    cout<<s3<<endl;
}

D - Dima and Lisa - [简单数论]

题解:

有一个命题:不小于 $6$ 的偶数都能表示成两个质数的和,然后 $4$ 可以表示成 $2+2$。

所以,我们只要让 $p_1 = 3$,那么剩下来 $n-3$ 必为偶数,就能找到两个质数加起来等于它,这要求最少也要筛 $1 \sim 5e8$ 的素数,会MLE。

因此,我们可以找出 $1e8,2e8,\cdots,9e8$ 这些数字附近的一个素数,然后例如 $n = 5e8+6e7$ 时,我们可以选 $p_1 = 5e8+9$,这样剩下来 $n - (5e8+9)$ 这个数的范围就保证在 $1 \sim 1e8$ 之间,然后我们只需要筛 $1 \sim 1e8$ 之间的素数就可以了。

AC代码:

#include<bits/stdc++.h>
using namespace std;
typedef pair<int,int> P;
int n;

const int MAX=1e8+50;
int cnt,prime[MAX/10];
bool isPrime[MAX+5];
void Screen() //欧拉筛法求素数
{
    cnt=0;
    memset(isPrime,1,sizeof(isPrime));
    isPrime[0]=isPrime[1]=0;
    for(int i=2;i<=MAX;i++)
    {
        if(isPrime[i]) prime[cnt++]=i;
        for(int j=0;j<cnt;j++)
        {
            if(i*prime[j]>MAX) break;
            isPrime[i*prime[j]]=0;
            if(i%prime[j]==0) break;
        }
    }
}

P Find(int sum)
{
    int p1=0, p2=cnt-1;
    while(p1<=p2 && prime[p1]+prime[p2]!=sum)
    {
        if(prime[p1]+prime[p2]>sum) p2--;
        else p1++;
    }
    return make_pair(prime[p1],prime[p2]);
}

int D[9]={(int)9e8-37,(int)8e8-1,(int)7e8+1,(int)6e8+1,(int)5e8+9,(int)4e8+9,(int)3e8+7,(int)2e8-9,(int)1e8+7};

int main()
{
    Screen();

    cin>>n;

    if(n==3)
    {
        printf("1\n");
        printf("3\n");
        return 0;
    }
    if(n==4)
    {
        printf("2\n");
        printf("2 2\n");
        return 0;
    }
    if(n==5)
    {
        printf("2\n");
        printf("2 3\n");
        return 0;
    }
    if(n==6)
    {
        printf("3\n");
        printf("2 2 2\n");
        return 0;
    }

    for(int i=0;i<9;i++)
    {
        if(n-D[i]>=4)
        {
            P res=Find(n-D[i]);
            printf("3\n");
            printf("%d %d %d\n",D[i],res.first,res.second);
            return 0;
        }
    }

    P res=Find(n-3);
    printf("3\n");
    printf("3 %d %d\n",res.first,res.second);
}

E - Anton and Ira - [贪心]

原文地址:https://www.cnblogs.com/dilthey/p/10542910.html

时间: 2024-10-12 11:14:16

Gym 240668 - A/B/C/D/E - (Done)的相关文章

Gym 240668E - Anton and Ira - [贪心]

题目链接:https://codeforces.com/gym/240668/problem/E 题意: 给两个 $1 \sim n$ 的排列 $p,s$,交换 $p_i,p_j$ 两个元素需要花费 $|i-j|$,要求你用最少的钱交换 $p$ 中的元素使得其变成 $s$. 题解: 思路很简单,给个例子如下: $p$:$5,1,2,3,4,6$ $s$:$3,4,1,6,2,5$ 我们不难发现,像: $p$:$5,1,\underline{2},\underline{3},4,6$ $s$:$\

CodeForces Gym 100935D Enormous Carpet 快速幂取模

Enormous Carpet Time Limit:2000MS     Memory Limit:65536KB     64bit IO Format:%I64d & %I64u Gym 100935D Description standard input/outputStatements Ameer is an upcoming and pretty talented problem solver who loves to solve problems using computers.

B - Average Gym - 101161B 组合数学

http://codeforces.com/gym/101161/attachments 今天被卡常了,其实是自己对组合数技巧研究的不够. 如果是n, m <= 1e5的,然后取模是质数,那么可以用费马小定理. 如果n, m都比较小,那么其实是直接杨辉三角.不用逆元那些. 这题的思路是,枚举每一一个ave,然后总和就是n * ave 相当于方程  x1 + x2 + .... + xn = n * ave中,在0 <= x[i] <= full的情况下,不同解的个数中,使得x[i] ==

Codeforces Gym 100269 Dwarf Tower (最短路)

题目连接: http://codeforces.com/gym/100269/attachments Description Little Vasya is playing a new game named "Dwarf Tower". In this game there are n different items,which you can put on your dwarf character. Items are numbered from 1 to n. Vasya want

CodeForces Gym 101063C 二进制压缩

http://codeforces.com/gym/101063/problem/C 给n个人,m样物品,每个人可以从物品中选择几样.两人选择物品的交集元素个数比上并集元素个数如果大于某个比例即可将两人配对.求配对数. n的范围是1e5,直接比较所有人的选择会TLE,应该将所有选择物品的情况用二进制压缩,m最大是10,情况数目小于2048,可以接受.注意配对总数范围应为long long. #define _CRT_SECURE_NO_WARNINGS #include <stdio.h> i

Gym 101246H ``North-East&#39;&#39;(LIS)

http://codeforces.com/gym/101246/problem/H 题意: 给出n个点的坐标,现在有一个乐队,他可以从任一点出发,但是只能往右上方走(包括右方和上方),要经过尽量多的点.输出它可能经过的点和一定会经过的点. 思路: 分析一下第一个案例,在坐标图上画出来,可以发现,他最多可以经过4个点,有两种方法可以走. 观察一下,就可以发现这道题目就是要我们求一个LIS. 首先,对输入数据排一下顺序,x小的排前,相等时则将y大的优先排前面. 用二分法求LIS,这样在d数组中就可

Gym 100712I Bahosain and Digits(开关翻转问题)

http://codeforces.com/gym/100712/attachments 题意: 给出一串数字,每次选择连续的k个数字加上任意数(超过10就取余),最后要使得所有数字都相等,求最大的k. 思路: 开关翻转问题. 算法具体可以参考<挑战程序竞赛>常用技巧篇. 这道题目就是在枚举k的同时再枚举一下最后要转换成的数字即可. 1 #include<iostream> 2 #include<algorithm> 3 #include<cstring>

很好的脑洞题:dfs+暴力 Gym - 101128A Promotions

http://codeforces.com/gym/101128 题目大意:给你一个a,b,e,p.有e个点,p条有向边,每条边为(x,y),表示x->y,每次我们都取出一个入度为0的,并且一次性取出来的个数为a(或b).当然,取出来的种类可能有很多种(即一个集合),问,这个集合中有多少个数字是相同的. 第一个输出集合长度为a的,第二个输出集合长度为b的,第三个输出无论如何都无法被取出的个数. 思路:建立正向图和反向图. 定义pair<int, int> interval[i] 表示第i

【树状数组】Gym - 101147J - Whistle&#39;s New Car

题意就是对每个点i,统计在其子树内(不含自身),且depj-depi<=xj的点有多少个. 把点分别按照dep-x和dep进行排序,离线处理, 每次把dep-x小于等于当前dep值的点插入树状数组,就变成了询问dfs序在一个区间内的点有多少个,可以用树状数组轻松解决. #include<cstdio> #include<algorithm> #include<cstring> using namespace std; int f,C; void R(int &am