Educational Codeforces Round 80 (Rated for Div. 2)

B,B:a*b+a+b=a*10b的位数+b。化简得知b+1=10b的位数。所以只有9,99,999……这样是可行的。

#include <bits/stdc++.h>
using namespace std;
const int maxn=4e5+10;
typedef long long ll;
ll n,m,ans;
char l,r;
char s[maxn];
int a[maxn];
int read(){
    char c=getchar();int x=0,f=1;
    while(c<'0'||c>'9'){if(c=='-')f=-1; c=getchar();}
    while(c>='0'&&c<='9'){x=x*10+c-'0'; c=getchar();}
    return x*f;
}
int work(int x)
{
    int ans=0;
    while(x){
        ans++;
        x/=10;
    }
    return ans;
}
int run(int x)
{
    int vis=0;
    while(x){
        if(x%10!=9) vis=1;
        x/=10;
    }
    if(vis==1) return 1;
    else return 0;
}
int main()
{
    int T;
    T=read();
    while(T--){
        n=read(),m=read();
        ll res=work(m);
        if(run(m)) res--;
        ll k=res*n;
        printf("%lld\n",k);
    }
}

C

给出n,m,表示你可以用1到n的元素组装出m个元素构成的字符串,如m=4,a=【1,1,1,3】 

现在给出要求,要求a,b两个数组,a数组不能下降,b数组不能上升,然后a的对应位置元素要小于等于b。

题解:

我们将b数组放过来看,就和a一样是不能下降,也就和a一样了,也就是2m长度的不下降的序列有多少个,直接dp

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=1e3+10;
const int P=1000000007;

ll DP[maxn][maxn];

int main()
{
    int n,m;
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;++i)DP[1][i]=1;
    for(int i=2;i<=2*m;++i){
        for(int j=1;j<=n;++j){
            for(int k=1;k<=j;++k){
                DP[i][j]=(DP[i][j]+DP[i-1][k])%P;
            }
        }
    }
    ll ans=0;
    for(int i=1;i<=n;++i){
        ans=(ans+DP[m][i])%P;
    }
    printf("%lld\n",ans);
    return 0;
}

  

D

给出n个数组每个数组有m个元素(注意m很小),你每次可以选择任一两个数组,ai和aj,然后组成新数组,新数组的每个元素都是从对应的位置的连个数组中挑选最大的。

问求所有组装方法中,这个新数组的最小元素是最大化的。

题解:

首先我们可以用二分方法来二分出这个值是多少,那二分的判断机制是什么?

就是判断当前这个值(因为这个值是新数组元素最小的,所以其他元素就得大于等于它)

同时我们发现这个m很小,故我们可以用状态压缩来表示状态。

具体实现方式:

我们利用状态压缩来表示a数组中每个元素是否大于x,如果大于等于,该位置就是1

例如a(1 2 3 4 0)x=2,那么就算01110.

然后记录当前状态是第几行得到的(多个相同状态也无所谓,随着x的提高也就是二分,我们会选出最优的那个的)。

然后接下来开始匹配,首先是i|j==lim,也就是表明每个位置都是1,每个位置都有元素,然后判断这两个状态是否有数组提供。

#include<stdio.h>
#define ri register int
#define il inline
const int M=300005;
const int N=12;
int p[N],id[M],a[M][N],n,m,o1,o2,lim;
bool ck(const int&x){
    ri i,j,res;
    for(i=0;i<=lim;++i) id[i]=0;//清空所有状态
    for(i=1;i<=n;++i){
        res=0;
        for(j=1;j<=m;++j)
            if(a[i][j]>=x) res|=p[j];//满足条件的状态压缩起来
        id[res]=i;//记录这个状态是抽出第行得到的
    }
    for(i=0;i<=lim;++i)//枚举i,j两个状态进行检查,是否可以抽出id[i]和id[j]以得到答案
        for(j=i;j<=lim;++j)//j从i枚举,以免重复计算
            if((i|j)==lim&&id[i]&&id[j])
                return o1=id[i],o2=id[j],1;
    return 0;
}
il void ms(){//MidSearch 即二分现在最大最小的b
    int l=0,r=1e9,mid;
    while(l<=r)
        mid=l+r>>1,ck(mid)?l=mid+1:r=mid-1;//满足条件,说明还可能存在较大解
}
int main(){
    scanf("%d%d",&n,&m);
    for(ri i=1,j;i<=n;++i)
        for(j=1;j<=m;++j) scanf("%d",&a[i][j]);
    lim=(1<<m)-1;
    for(ri i=1;i<=m;++i) p[i]=1<<i-1;//常数优化
    ms(),printf("%d %d\n",o1,o2);//输出任意一组满足条件的解即可
    return 0;
}

  

posted on 2020-01-16 17:36  师姐的迷弟  阅读(118)  评论(0编辑  收藏  举报

导航