BestCoder 2nd Anniversary A,B,C解题报告

来源:互联网 发布:type3软件下载 编辑:程序博客网 时间:2024/06/18 06:07

【A题】

【题意】给一个数字构成的字符串,可以任意交换这个字符串里面的任意位置!在交换之后,要把这个字符串拆成两个数,使得它们的和,最大,并且输出这个拆掉之后的字符串!

【解题方法】水题,先记录 0−90-909101010个数字分别有多少个。不难看出,最小的一个存在的数字和其余的数字降序排列的相加就是答案,但是最小的那个数字不能是000,因为题面上说明是正整数。将这两个数加起来时,注意处理进位问题。考虑无解的情况,即一串数字中仅存在111个非000数字或不存在。

【AC code】

#include <cstdio>#include <cstring>#include <iostream>#include <algorithm>using namespace std;#define ll long longchar s[20000000];int a[10];string ans;int main(){    int t;    scanf("%d",&t);    while(t--)    {        memset(a,0,sizeof(a));        ans="";        scanf("%s",s);        int len=strlen(s);        int p=0;        for(int i=0; i<len; i++)        {            if(s[i]!='0') p++;        }        if(p<2)        {            puts("Uncertain");            continue;        }        for(int i=0; i<len; i++)        {            a[s[i]-'0']++;        }        int x=0;        ans="";        for(int i=1; i<=9; i++)        {            if(a[i])            {                x=i;                a[i]--;                break;            }        }        for(int i=9; i>=0; i--)        {            if(a[i])            {                while(a[i])                {                    ans+=char(i+'0');                    a[i]--;                }            }        }        int l=ans.size();        int zz=x;        //cout<<ans<<endl;        bool flag=0;        for(int i=l-1; i>=0; i--)        {            if(ans[i]-'0'+zz>=10)            {                ans[i]=(ans[i]-'0'+zz-10)+'0';                flag=1;                zz=1;            }            else            {                ans[i]=(ans[i]-'0'+zz)+'0';                zz=0;            }        }        if(flag) printf("%c",ans[0]-'0'+zz+'0');        for(int i=0; i<=l-1; i++)        {            printf("%c",ans[i]);        }        printf("\n");    }    return 0;}

【B】

【题意】给了n个数B[i]和n个数C[i]。B[i]代表在【1--i】里面的最小值为B【i】,C【i】代表在【1--i】里面的最大值为C【i】,现在要求一个1--n的排列,使得这个排列满足上述条件,问有多少个这样的排列?

【解题方法】规律题!

可以发现A1=B1=C1 A_1 = B_1 = C_1A1=B1=C1,所以如果B1≠C1 B_1 \neq C_1 B1C1无解。

进一步,我们发现如果Bi<Bi−1 B_i < B_{i-1}Bi<Bi1Ai=Bi A_i = B_i Ai=Bi;如果Ci>Ci−1 C_i > C_{i-1} Ci>Ci1Ai=Ci A_i = C_i Ai=Ci。但是如果Bi<Bi−1 B_i < B_{i-1} Bi<Bi1Ci>Ci−1 C_i > C_{i-1} Ci>Ci1同时满足,就会产生冲突导致无解。

考虑Bi=Bi−1 B_i = B_{i-1} Bi=Bi1Ci=Ci−1 C_i = C_{i-1} Ci=Ci1同时满足的情况,此时应有Ai∈(Bi,Ci) A_i \in (B_i,C_i) Ai(Bi,Ci)Ai A_i Ai没有在之前使用过。因为(Bi,Ci) (B_i,C_i) (Bi,Ci)是不断变大的,我们只需维护一下这个区间内有多少值已经被使用过了,用乘法原理统计答案即可。注意到如果某时刻Ai A_i Ai没有值可以使用,也会导致无解。

时间复杂度O(Tn) O(Tn) O(Tn)

【AC代码】

#include <bits/stdc++.h>using namespace std;#define ll long longconst ll mod=998244353;const int maxn=1e5+5;int B[maxn],C[maxn];int main(){    int T,n;    scanf("%d",&T);    while(T--)    {        scanf("%d",&n);        for(int i=1; i<=n; i++) scanf("%d",&B[i]);        for(int i=1; i<=n; i++) scanf("%d",&C[i]);        if(B[1]!=C[1])        {            puts("0");            continue;        }        ll ans=1;        for(int i=2; i<=n; i++)        {            if(B[i]<B[i-1]&&C[i]>C[i-1])            {                ans=0;                break;            }            if(B[i]!=B[i-1]&&C[i]!=C[i-1])            {                ans=0;                break;            }            if(B[i]==B[i-1]&&C[i]==C[i-1])            {                ans=ans*max(C[i]-B[i]+1-(i-1),0)%mod;            }        }        printf("%I64d\n",ans);    }}

【C】

【题意】

首先给出n,L,R,表示地上现在有n根树枝,你手里现有[L,R]长度的树枝各一根要求选择一根树枝,不能与地上任意两根树枝构成三角形,问有多少种选法。

【解题方法】

考虑三角形三条边a,b,c a,b,c a,b,c(a≥b) (a \ge b) (ab)的关系a−b<c,a+b>c a - b < c, a + b > c ab<c,a+b>c,即c∈(a−b,a+b) c \in (a-b,a+b) c(ab,a+b)

令加入的边为c c c,枚举所有边作为a a a的情况。对于所有可行的b b b,显然与a a a相差最小的可以让(a−b,a+b) (a-b,a+b) (ab,a+b)覆盖范围最大,所以可以贪心地选择不大于a a a的最大的b b b

于是我们可以先将边按长度排序,然后ai a_i aiai+1 a_{i + 1} ai+1建一条线段。线段并是不合法的部分。

将所有线段按左端点排序,按序扫描一遍,过程中统计答案即可。

时间复杂度O(Tn logn) O(Tn\ \log n)O(Tn logn)

【AC code】

#include <bits/stdc++.h>using namespace std;#define ll long longconst int maxn=1e5+5;ll a[maxn];pair<ll,ll>p[maxn];ll ans;ll L,R;int n;int main(){    int T;    scanf("%d",&T);    while(T--)    {        scanf("%d%I64d%I64d",&n,&L,&R);        for(int i=1; i<=n; i++) scanf("%I64d",&a[i]);        sort(a+1,a+n+1);        for(int i=1; i<n; i++)        {            p[i].first=a[i+1]-a[i];            p[i].second=a[i+1]+a[i];        }        sort(p+1,p+n);        ll mx=L;        ll ans=0;        for(int i=1; i<n&&p[i].first<=R; i++)        {            if(p[i].first>=mx) ans+=(p[i].first-mx+1);            mx=max(mx,p[i].second);        }        ans+=max((ll)0,R+1-mx);        printf("%I64d\n",ans);    }}



0 0
原创粉丝点击