Educational Codeforces Round 80

QAQ:

其中C,D,E题的思路来自

https://www.bilibili.com/video/av83609526?p=5

A. Deadline

题意:

给出一个式子对于给出的d,求当x是整数时的最小解。

思路:

简单数学题,这个式子变形一下就是我们中学学的对号函数,但要注意下向上取整和整数x

代码:

#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
int main()
{
    int T;
    LL n,d;
    cin >> T;
    while(T--)
    {
        cin >> n >>d;
        LL x = sqrt(d);
        if(d<=n)
        {
            printf("YES\n");
            continue;
        }
        if(2*x-1>n)
            printf("NO\n");
        else
        {
            if(x*x==d)
            {
                int ans = 2*x-1;
                if(ans<=n)
                    printf("YES\n");
                else
                    printf("NO\n");
            }
            else
            {
                int x1 = x,x2 = x+1;
                int ans1 = d/x1,ans2 = d/x2;
                if(d%x1)
                    ans1++;
                if(d%x2)
                    ans2++;
                ans1 += (x1-1);
                ans2 +=(x2-1);
                if(ans1<=n||ans2<=n)
                    printf("YES\n");
                else
                    printf("NO\n");
            }
        }
    }
    return 0;
}

B.  Yet Another Meme Problem

题意:

给你两个数,A,B,要求有多少对a,b(),满足a*b+a+b = conc(a,b),其中conc(a,b),表示将a和b连接起来,例如conc(12,23) = 1223。

思路:

我们可以将给出的公式变一下形

所以最终结果等于A*(满足上面取值的b的数目)。

代码:

#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
int main()
{
   int T;
   cin >> T;
   while(T--)
   {
       LL A,B;
       cin >> A >>B;
       B++;
       int cnt = 0;
       while(B)
       {
           cnt++;
           B/=10;
       }
       --cnt;
       cout << A*cnt << endl;
   }
    return 0;
}

C.  Two Arrays

题意:

给你两个数n,m,要求你用1-n中的数组成两个长为m的数组a,b,要求a数组非递减,b数组非递减,同时,求这样的数组共有多少对(结果mod

思路:

根据上面的条件我们可以把上面两个数组倒接,如下所示

现在问题转化为用1-n中的数构造出一个长为2*m的非递减数组,问最多有多少组合。

我们可以用表示i这个数选用了多少次。

那么

考虑组合数学来解决问题。

上面可转为2*m个球放进n个盒子,盒子可以为空的组合数,进而可以转为将2*m+n个球分成n份,每份不允许为空的方案数。

运用隔板法,那么最终答案是就是

也就是,组合数取模的话,可以用卢卡斯定理 解决。

代码:

#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const LL mod = 1e9+7;
LL quick_pow(LL x, LL n, LL p)// 快速幂求x^n mod p 的结果
{
    if(n==0)
        return 1;
    if(n==1)
        return x%p;
    LL ans = 1;
    LL tmp = x%p;
    while(n)
    {
        if(n&1)
        {
            ans = (ans*tmp)%p;
        }
        tmp = tmp*tmp%p;
        n>>=1;
    }
    return ans%p;
}
LL inv(LL b,LL p) //求数 b mod p 的逆元
{
    return quick_pow(b,p-2,p);
}
LL C(LL n,LL m,LL p)//组合数取模
{
    if(m==0|| m== n)
        return 1;
    if(m==1||m==n-1)
        return n%p;
        m = min(m,n-m);
    LL up = 1,down = 1;
    for(LL i = n-m+1;i<=n;i++)
        up=(up*i)%p;
    for(LL i = 1;i<=m;i++)
        down*=i%p;
    up%=p;
    down%=p;
    return (up*(inv(down,p)%p))%p;
}
LL lucas(LL n,LL m,LL p)//递归lucas函数
{
    if(m==0)
        return 1;
    return lucas(n/p,m/p,p)*C(n%p,m%p,p)%p;
}
int main()
{
    LL n,m;
    cin >> n >> m;
    cout << lucas(2*m+n-1,2*m,mod);
    return 0;
}

D.  Minimax Problem

题意:

给你一个大小为n*m的矩阵,让你任取两行,取对应列的两个数的较大者构成新的一行,并使这一行中的最小的数最大。输出结果的两行(这两行可以是同一行)

思路:

最大化最小值的问题,考虑二分解决。但是二分的对象是那个最大的最小值。

这个题的check函数比较特殊。

观察题目,m的范围很小,我们可以将考虑将每一行映射成为二进制,具体规则是(假设check的数是k),这一行大于等于k的数为1,小于的为0,假如我们选出的两列或的结果就是合并出来的行二进制下的结果,如果结果大于(1<<m)-1,也就是二进制下m个1,就代表当前的这个数是可以的。具体细节可以代码。

代码:

#include <bits/stdc++.h>
using namespace std;
int n,m;
vector<vector<int> >a;
int a1,a2;
bool can(int mid)
{
    vector<int>msk(1<<m,-1);
    for(int i = 0;i<n;++i)
    {
        int cur =0;
        for(int j = 0;j<m;++j)
        {
            if(a[i][j]>=mid)
                cur^=(1<<j);
        }
        msk[cur] = i;
    }
    if(msk[(1<<m)-1]!=-1)
    {
        a1 = a2 =msk[(1<<m)-1];
        return true;
    }
    for(int i = 0;i<(1<<m);++i)
        for(int j = 0;j<(1<<m);++j)
    {
        if(msk[i]!=-1&&msk[j]!=-1&&(i|j)==(1<<m)-1)
        {
            a1 =msk[i];
            a2 =msk[j];
            return true;
        }
    }
    return false;
}
int main()
{
    scanf("%d %d",&n,&m);
    a.resize(n,vector<int>(m));
    for(int i= 0;i<n;++i)
        for(int j = 0;j<m;++j)
            scanf("%d",&a[i][j]);
    int lf =0;
    int rg = int(1e9)+43;
    while(rg-lf>1)
    {
        int m = (lf+rg)/2;
        if(can(m))
        lf = m;
        else
            rg = m;
    }
    printf("%d %d\n",a1+1,a2+1);
    return 0;
}

E.  Messenger Simulator

题意:

给你一个1-n的序列,输出m个数(1-n之间),代表把这数提到首位,求每个数在序列里的最小最大位置。

思路:

可以考虑在1-n之前插入m个空位,构成一个长为n+m的数组,假设是第i次输入的数是x,就把x放在m-i+1的位置,这个数原先所在的位置变成0,每次更新下所求的两个值,最后再更新一下即可,整个结构可以用树状数组来维护,具体细节可以代码。

代码:

#include <bits/stdc++.h>
using namespace std;
const int maxn = 1e6+7;
int n,m;
int a[maxn],d[maxn],mx[maxn],mn[maxn];
int pos[maxn];
int lowbit(int x)
{
    return x&(-x);
}
void update(int x,int y)
{
    for(int i =x;i<maxn;i+=lowbit(i))
        d[i]+=y;
}
int get(int x)
{
    int ans =0;
    for(int i =x;i;i-=lowbit(i))
        ans+=d[i];
    return ans;
}
int main()
{
    cin >> n >> m;
    for(int i =1;i<=n;++i)
    {
        mx[i] = mn[i] = i;
        pos[i] = i+m;
        update(i+m,1);
    }
    for(int i =0;i<m;++i)
    {
        int x;
        cin >> x;
        mx[x] = max(mx[x],get(pos[x]));
        mn[x] = 1;
        update(pos[x],-1);
        pos[x] = m-i;
        update(pos[x],1);
    }
    for(int i = 1;i<=n;++i)
    {
        mx[i] = max(mx[i],get(pos[i]));
    }
    for(int i = 1;i<=n;++i)
        cout << mn[i] << " " << mx[i] << "\n";
    return 0;
}

原文地址:https://www.cnblogs.com/baihualiaoluan/p/12274317.html

时间: 2024-10-09 04:33:37

Educational Codeforces Round 80的相关文章

Educational Codeforces Round 80 (Rated for Div. 2)

\[Educational\ Codeforces\ Round\ 80\ (Rated\ for\ Div.\ 2)\] A.Deadline 打勾函数找最小值,在\(\sqrt{d}\)邻域里找\(x\)最小化\(x+\lceil\frac{d}{x+1}\rceil\)即可 //#pragma comment(linker, "/STACK:1024000000,1024000000") #include<bits/stdc++.h> using namespace

Educational Codeforces Round 80 (Rated for Div. 2)(C - Two Arrays )

C - Two Arrays 题目链接:https://codeforces.com/contest/1288/problem/C 题目: 题意:给你n,m,利用1~n之间的数(可重复)来组成长度为m的数组a,b,要求数组a非递减,数组b非递增,且a数组的数<=b数组中的数,求出a,b数组对数 思路:用动态规划,dp[i][j]是第i个位置放数字j的方案数,根据题意可以将b数组反置然后接在a后面,则该数组长度为2m,为一个非递减序列,则就是求1~n这些数字可重复组成多少种长度为2m的非递减序列,

Educational Codeforces Round 80 (Rated for Div. 2)参加感悟

这次比赛有14000+的人报名,结果我得了266名,创了新纪录. 进过这次比赛,我有回答了1800+. 寒假到了,又可以每次比赛都打了.平时进步很慢,我希望能在寒假有更大的进步. 作为寒假第一场比赛,发挥让我还是很满意的. 开始讲题: A: http://codeforces.com/contest/1288/problem/A 这题太水了,直接是sqrt(d)-1和sqrt(d),如果它们不行,那么其他的也肯定不行. 直接上代码: 1 #include<bits/stdc++.h> 2 #d

Educational Codeforces Round 80 A-E简要题解

contest链接:https://codeforces.com/contest/1288 A. Deadline 题意:略 思路:根据题意 x + [d/(x+1)] 需要找到一个x使得上式小于等于n,即x + [d/(x+1) ] <=n,不等式两边同时+1得 x+1 + [d/(x+1)] <=n + 1当且仅当(x+1)2 = d时,式子左边最小,所有只需要判断一下最小值是否<=n+1就可以知道该不等式是否存在x满足题意了,即找到x = √d - 1,判断一下即可. AC代码:

Educational Codeforces Round 80 C. Two Arrays

http://codeforces.com/contest/1288/problem/C 题意: 用1—n构造两个长为m的数组a,b 满足a[i]<=b[i],a单调不减,b单调不增 求方案数 令dp[i][j][k] 表示构造了长度为i,a[i]=j,b[i]=k的方案数 dp[i][j][k]=Σ dp[i-1][h][p] (h<=p,h<=i,p>=k) 时间复杂度:m*n^4 前缀和.后缀和 优化: sum[i][j][k] 表示 Σ dp[i][1—j][k—n] 求的

Educational Codeforces Round 80 E. Messenger Simulator

http://codeforces.com/contest/1288/problem/E 题意: 有一个长度为n的循环队列,初始第i个位置的数字为i 有m次操作,每次操作把数字x放到队首,原队首与数字x原位置之间的数字在队列中后移一位 输出m次操作过程中,数字i在队列中最靠前和最靠后的位置 若数字i没有移动过, 它最靠前的位置就是初始位置i, 最靠后的位置就是初始位置加上移动过的大于它的数字个数 若数字i被移动过 它最靠前的位置就是1 最靠后的位置是max(初始位置加上第一次移动前移动的大于它的

Educational Codeforces Round 80. A - Deadline

题面:https://codeforces.com/contest/1288/problem/A 题目大意: Adilbek有一个特殊项目,他需要运行这个项目得到结果. 但是这个项目直接运行需要消耗d天时间. 他也可以选择优化程序以减少程序运行消耗时间. 假设他用了x天优化程序,那么最后运行程序只需要消耗天的时间(括号指向上取整). 那么总共需要消耗的天数是. 问,他能不能在n天内得到结果? 解题思路: 问能不能在n天内得到结果,只需要求出最少需要的天数与n对比即可. 可得到 那么总天数为 当且

Educational Codeforces Round 80. B - Yet Another Meme Problem

题面:https://codeforces.com/contest/1288/problem/B 题目大意: 令conc(a,b)函数得出的结果为将ab拼接得到的数字. 例如:conc(12,23)=1223 a和b不会包括前导0! 接下来,你已知A和B,问有多少对的(a,b)满足 1≤a≤A , 1≤b≤B a*b+a+b=conc(a,b) 解题思路: 想法题,只需要满足b这个数字每一位全为9,那么等式 a*b+a+b=conc(a,b) 恒成立 因为 a*b+a+b=a*(b+1)+b b

Educational Codeforces Round 80. D - Minimax Problem

题面:https://codeforces.com/contest/1288/problem/D 题目大意: 给定n个序列,每个序列元素个数严格相等于m 你需要找到两个序列a[i]和a[j],使其每个对应位置的元素取大后得到b序列  b[k]=max(a[i][k],a[j][k]) 且让b序列中的最小值最大 i可以等于j 解题思路: 二分假设这个b序列的最小值的值x 将a序列转化成01构成的二进制串存在数组b中 0表示当前位置的值<x 1表示当前位置的值>=x 每次便最多可以得到3e5个字符

Educational Codeforces Round 80 (Rated for Div. 2(A Deadline )

(A) Deadline 题目: 思路:一开始还傻傻的暴力康康....只要求出令x=n的一半就行,然后判断 1 #include<bits/stdc++.h> 2 using namespace std; 3 int main() 4 { 5 //freopen("text","r",stdin); 6 int T; 7 scanf("%d",&T); 8 while(T--) 9 { 10 //cout<<cei