【A题】
【题意】给一个数字构成的字符串,可以任意交换这个字符串里面的任意位置!在交换之后,要把这个字符串拆成两个数,使得它们的和,最大,并且输出这个拆掉之后的字符串!
【解题方法】水题,先记录 0−90-90−9这101010个数字分别有多少个。不难看出,最小的一个存在的数字和其余的数字降序排列的相加就是答案,但是最小的那个数字不能是000,因为题面上说明是正整数。将这两个数加起来时,注意处理进位问题。考虑无解的情况,即一串数字中仅存在111个非000数字或不存在。
【AC code】
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
#define ll long long
char 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_1 A1=B1=C1,所以如果B1≠C1 B_1 \neq C_1 B1≠C1无解。
进一步,我们发现如果Bi<Bi−1 B_i < B_{i-1} Bi<Bi−1,Ai=Bi A_i = B_i Ai=Bi;如果Ci>Ci−1 C_i > C_{i-1} Ci>Ci−1,Ai=Ci A_i = C_i Ai=Ci。但是如果Bi<Bi−1 B_i < B_{i-1} Bi<Bi−1和Ci>Ci−1 C_i > C_{i-1} Ci>Ci−1同时满足,就会产生冲突导致无解。
考虑Bi=Bi−1 B_i = B_{i-1} Bi=Bi−1和Ci=Ci−1 C_i = C_{i-1} Ci=Ci−1同时满足的情况,此时应有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 long
const 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) (a≥b)的关系a−b<c,a+b>c a - b < c, a + b > c a−b<c,a+b>c,即c∈(a−b,a+b) c \in (a-b,a+b) c∈(a−b,a+b)。
令加入的边为c c c,枚举所有边作为a a a的情况。对于所有可行的b b b,显然与a a a相差最小的可以让(a−b,a+b) (a-b,a+b) (a−b,a+b)覆盖范围最大,所以可以贪心地选择不大于a a a的最大的b b b。
于是我们可以先将边按长度排序,然后ai a_i ai和ai+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 long
const 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);
}
}