EDU div2#80 真丶被教育场

主宰稳场 提交于 2020-01-16 02:38:47

许久没打cf果然会变的好捞

C. Two Arrays

题目链接:https://codeforces.com/contest/1288/problem/C

题目大意   有两个长度为m的数组 a,b,a 非降序,b非升序   bi>=ai      1<=ai,bi<=n

问满足条件的  a b数组有多少个

  

将B数组翻转一下     bm>=am

则原题变为长度为2m的非降序数组有多少个,这就是个十分煞笔的DP

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=3e5+7;
const ll mod=1e9+7;
int dp[1007][22];
int main()
{
    int n,m;
    cin>>n>>m;
    for(int i=1;i<=n;i++)
        dp[i][1]=1;
    for(int j=1;j<=n;j++)
    {
        for(int i=2;i<=m*2;i++)
        {
            dp[j][i]=(dp[j][i-1]+dp[j-1][i-1])%mod;
        }
    }
    ll sum=0;
    for(int i=1;i<=n;i++)
    {
       sum+=dp[i][m*2];
       sum%=mod;
    }
    cout<<sum<<endl;
}

当然也有其他的很多好的方法,比如

翻转+公式法   C(2m,2m+n-1);直接就是答案

 

比如,不翻转

用二维数组保存答案,二维差分维护   dp[i][j]   i表示第i位,j表示第i位放的值

则递推公式为 dp[i][j]=dp[i-1][j]+dp[i][j-1]-dp[i-1][j-1]+1;

 

D. Minimax Problem

题目链接:https://codeforces.com/contest/1288/problem/D

题目大意:选两个数组   每个位上的数字取两个数组该位置较大值 得到新的数组B   要使B数组最小值最大   输出你要选择的两个数组

思路  二分枚举B数组的最小值   然后比较每个数组和mid   会得到100010 类似的字符串s  二进制值记为sss   然后我们想要这个字符串1出现位置的子集,枚举1-2^m   如果  i&sss==i 则说明i是sss的子集,怎么判断mid成立与否呢,那就是例如 101101,只要010010存在就可以了,前面的子集部分都用一个数组存放的话就可以了,然后保存最后一个成立的数组的下标,和B数组最小值,然后暴力找前面的另一个满足条件的数组就可以了

代码有些乱,懒得优化了

好吧!还是整理了下,毕竟懒得已经只会去找容易的事情做了

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=3e5+7;
const ll mod=1e9+7;
int di[N][10];
int n,m,ma,ans,tt;
int solve(int x)
{

       int f=0;
        int mid=x;
        int pan[300]={0};
        pan[0]=1;
        for(int i=0;i<n;i++)
        {
            int sss=0;
            for(int j=0;j<m;j++)
            {
                if(di[i][j]>=mid)
                {
                    sss+=(1<<j);
                }
            }
            //cout<<ma<<' '<<sss<<'?'<<endl;
            //cout<<pan[1]<<endl;
            if(pan[ma-sss]==1){ans=i;tt=sss;return 1;}
            for(int ii=1;ii<ma;ii++)
            {
                int d=(ii&sss);
                if(d==ii)
                {
                    pan[ii]=1;
                }
            }
        }
        return 0;
}
int main()
{
    scanf("%d%d",&n,&m);
    for(int i=0;i<n;i++)
        for(int j=0;j<m;j++)
           scanf("%d",&di[i][j]);
    int l=0;
    int r=1e9;
    ma=(1<<m)-1;
    while(l<r)
    {
       int f=0;
        int mid=(l+r)/2;
        if(solve(mid))
            l=mid+1;
        else
            r=mid;
    }
    if(!solve(l)) l--;
    int ans2=0;
    for(int i=0;i<n;i++)
    {
        int sss=0;
        for(int j=0;j<m;j++)
        {
            if(di[i][j]>=l)
            {
                sss+=(1<<j);
            }
        }
        int d=ma-tt;
        d=d&sss;
        if(d==(ma-tt)) {ans2=i;break;}
    }
    printf("%d %d\n",ans2+1,ans+1);
}

 

 

赛前报名一时爽,赛后补题火葬场

比赛我唯唯诺诺,赛后我重拳出击

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!