20240802
赛时得分
| 题目 | A | B | C | D | E | F | G | H | 总分 | 排名 | 比例 |
|---|---|---|---|---|---|---|---|---|---|---|---|
| 满分 | 1200 | 1300 | 1400 | 1700 | 1800 | 1900 | 2300 | 2600 | 14700 | 181 | 100% |
| 得分 | 1200 | 1300 | 238 | 680 | 90 | 57 | - | 78 | 3638 | 159 | 87.8% |
A. 俄罗斯国旗(1200/1200)
\(\text{100%}\) 得分做法,一眼数据范围 \(3\leq N,M\leq 50\),直接四重循环枚举白蓝和蓝红的边界,然后直接数一下涂色的格子,最后取一手 min 值即可。
#include<bits/stdc++.h>
#define Std_Maker lhm
#define ll long long
using namespace std;
const int N=51;
string s[N];
ll n,m,ans,minn=2147483648,cnt;
int main()
{
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
cin>>n>>m;
for(int i=1;i<=n;i++)
{
cin>>s[i];
s[i]=" "+s[i];
}
for(int i=1;i<n-1;i++)
{
for(int j=i+1;j<n;j++)
{
cnt=0;
for(int k=1;k<=i;k++)
{
for(int l=1;l<=m;l++)
{
if(s[k][l]!='W') cnt++;
}
}
for(int k=i+1;k<=j;k++)
{
for(int l=1;l<=m;l++)
{
if(s[k][l]!='B') cnt++;
}
}
for(int k=j+1;k<=n;k++)
{
for(int l=1;l<=m;l++)
{
if(s[k][l]!='R') cnt++;
}
}
minn=min(cnt,minn);
}
}
cout<<minn;
return 0;
}
B. 被感染的二进制数(1300/1300)
\(\text{100%}\) 得分做法,这道题其实就是二进制与十进制之间的乘法。
这种题的做法其实就是对于一个二进制串 \(s\),我们把它反转然后存到一个 ll 类型的数组里,然后一位一位乘上十进制数 \(mul\),进行二进制下的进位运算,我们开一个变量 cnt 来模拟进位的数,在下一位乘上十进制数时加上上一位的进位,即 \(a_i=a_i\times mul+cnt\)。
进位的计算方法就是当位加上进位后的总和 \(a_i\) 除以 \(2\),而为了转化为二进制数,我们需要将 \(a_i\ \text{mod}\ 2\) 转化为当为的二进制。
整个过程是一直循环的,我们开一个 while,条件是 i<=s.length() or cnt>0,原因是当 i<=s.length() and cnt>0 时,说明转换操作已经全部到位了。
\(i\) 表示进位的位数,初始值是 \(1\),最后要减掉。
#include<bits/stdc++.h>
#define Std_Maker lhm
#define ll long long
using namespace std;
ll a[1001],i=1,cnt;
string s;
int main()
{
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
cin>>s;
for(int i=1;i<=s.length();i++) a[i]=s[s.size()-i]-'0';
while(i<=s.length() or cnt>0)
{
a[i]=a[i]*17+cnt;
cnt=a[i]/2;
a[i]%=2;
i++;
}
i--;
for(;i>=1;i--) cout<<a[i];
return 0;
}
C. 造篱笆(1400/1400)
\(\text{100%}\) 得分做法,看数据范围本题的 \(h\leq 2000\),这时我们要枚举答案使得复杂度降低。由于是两板长度之和,因此我们从 \(1\) 枚举到 \(4000\),再开一层 \(1\) 到 \(i\) 的循环,找一下已经存在的 \(h_j\) 和 \(h_{i-j}\) 的个数,因为 \(j+(i-j)=i\),也是我们的答案,这时取到二者 min 值就是我们在这个答案下可以找到的个数。
在这一个答案 \(i\) 所有对应的 \(j\) 枚举结束后,我们统计一下答案总个数 sum,如果 sum>maxn 的话,我们更新 maxn=sum,然后方案数归为 \(1\);如果 sum=maxn,方案数就可以加一了。
最后别忘了是两个板加在一起的长度,最后的 maxn 我们要除以二。
#include<bits/stdc++.h>
#define Std_Maker lhm
#define ll long long
using namespace std;
const int N=1e6+1;
ll n,a,h[N],sum,maxn,ans;
int main()
{
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
cin>>n;
for(int i=1;i<=n;i++)
{
cin>>a;
h[a]++;
}
for(int i=1;i<=4001;i++)
{
sum=0;
for(int j=1;j<=i;j++) sum+=min(h[j],h[i-j]);
if(sum==maxn) ans++;
if(sum>maxn) maxn=sum,ans=1;
}
cout<<maxn/2<<" "<<ans;
return 0;
}
D. 回文数字(1700/1700)
\(\text{100%}\) 得分做法,下午补题的时候写了 90min 才写完,这道题的细节确实非常多。
这道题的要点有几个,首先应该想到对一个串 ABCD,我们应首先尝试把它变化成 ABBA 的形式,然后判断 ABBA 是否大于 ABCD,若大于就可以直接输出,如果小于的话,我们应选择将 B 位加一再输出。
看起来这道题的大致思路就这样,然而我们接下来面对的是很多的细节。
- 长度为奇数的串的处理:对于一个串
ABCDE,我们应想到将其转化为ABCBA的形式,同样的,如果需要进行加一操作的话,我们需要操作的对象是C位。 - 由于本题的串长度有 \(10^6\),直接比较数字的大小或进行加法操作是不现实的,所以我们要分别写两个函数来维护比较和加一的操作。对于比较操作,首先判断串长,若相同就利用
stoi和to_string函数在ll和string之间反复转化逐个比较字符即可;对于加一操作,我们仍然利用上述两个函数取出操作位进行加一,然后再转换回去即可。 - 接下来就有一种特殊情况,即
999这种类型的数字加一转化,如果像刚才说的那样转化,我们所得到的字符串是9910,这显然是错误的,那么我们需要从后往前枚举每一位,是 \(9\) 我们就把这一位换成 \(0\),然后直到不是 \(9\) 的那一位我们加一即可。 - 接着你会发现如果是
9999的话,按照操作三结束后我们得到的串是100001,这显然也是不对的,那么其实很简单,我们删掉一个 \(0\) 即可。 - 最后,如果是 \(0\) 这种一位数的话,我们特判一下,其实直接枚举到一个回文数输出即可。也就是常数次,可视作 \(\mathcal{O}(1)\)。
然后这道题就写完了。
#include<bits/stdc++.h>
#define Std_Maker lhm
#define ll long long
using namespace std;
string s,s1,s2,s3,s4;
ll l,l1,ans;
bool ok=0;
bool check(ll n)
{
string s1,s2;
s1=to_string(n);
s2=s1;
reverse(s1.begin(),s1.end());
if(s1==s2) return 1;
return 0;
}
string plus1(string s,ll l)
{
ll i=l;
string s2,num1;
while(1)
{
num1="";
num1+=s[i];
if(num1=="9")
{
if(i==0)
{
s2="10"+s2;
ok=1;
return s2;
}
s2+="0",i--;
}
else
{
ll m=stoi(num1);
m++;
num1=to_string(m);
s2=s.substr(0,i)+num1+s2;
return s2;
}
}
}
bool pd(string a,string b)
{
ll l1=a.length(),l2=b.length(),val1,val2;
string c,d;
if(l1>l2) return 1;
else if(l1<l2) return 0;
for(int i=0;i<l;i++)
{
c="",d="";
c+=a[i],d+=b[i];
val1=stoi(c),val2=stoi(d);
if(val1<val2) return 0;
else if(val1>val2) return 1;
}
return 0;
}
int main()
{
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
cin>>s;
l=s.length();
if(l==1)
{
ans=stoi(s);
for(int i=ans+1;;i++)
{
if(check(i)==1)
{
cout<<i;
return 0;
}
}
}
if(l%2==0)
{
s1=s.substr(0,l/2);
s3=s1,s4=s1;
reverse(s3.begin(),s3.end());
s4+=s3;
if(pd(s4,s)==0)
{
s1=plus1(s1,l/2-1);
if(ok==1)
{
ll len1=s1.length();
s2=s1.substr(0,len1-1);
reverse(s2.begin(),s2.end());
s1+=s2;
cout<<s1;
return 0;
}
s2=s1;
reverse(s2.begin(),s2.end());
s1+=s2;
cout<<s1;
}
else cout<<s4;
}
else
{
s1=s.substr(0,l/2+1);
s4=s1;
l1=s.length();
s3=s1.substr(0,l1/2);
reverse(s3.begin(),s3.end());
s4+=s3;
if(pd(s4,s)==0)
{
s1=plus1(s1,l/2);
l1=s.length();
s2=s1.substr(0,l1/2);
reverse(s2.begin(),s2.end());
s1+=s2;
cout<<s1;
}
else cout<<s4;
}
return 0;
}
这破题写了 125 行,虽然说很傻,但从某个角度上来看我很佩服我自己。

浙公网安备 33010602011771号