大二,第二次参加ccpc线下比赛,没有发挥好,思路有些乱,没有静下心去思考,到最后无脑硬猜结论,导致只与队友ac三道题,获得省赛铜牌。
开始两分钟的时候看有人把签到题F过了,就先去敲签到,怕罚时还多测试了几组数据,交一发过了,于是跟队友开始写b题,一开始以为是个dp,我就想先敲状态dp的代码,但是发现初始状态跟转移方程有些难推,于是考虑贪心解法,当时我有个思路,取后缀min,将把金币留给后面小的花费时再购买,于是先开了个数组,但是队友让我用map存下标位置,一开始不是很理解,但是听完他讲完之后发现思路大致相同,就是还在自己的思维当中,不会队友的实现过程,就给队友操作了,敲出来之后我们还是测了几发自己出的数据,发现没问题就交了,也是一发过(赛后用自己的思路写发现也是能过的,不过比赛中我觉得还是要综合队友思路,合作将思维漏洞缩到最小),第三题写的J题,看题目只有五位数,跑一个全排列next_permutation肯定能暴力过的,但是队友发现了其中的性质,也算是本题的特殊解法吧,算是将o(n*5!)优化到了o(n),不过两种都能过,注意到前导零这个小细节处理一下也是一发就过,到此为止三道题都是一次过的,没有任何罚时,解完之后大概在国铜的铜首(在当时一个小时以内ac三道题无罚时已经是咱学校最好的成绩了)。但后面的四个小时我们一道题都没过!!!H取模忘记每两个数相乘都要取模,爆了long long,M我作为队长甚至想投机取巧猜结论,压根没去想二分!!!这是我觉得本次比赛我最大的失误。而且L的简单线性dp也没有去写(当时转移方程已经推出来了,就是卡在H、M两题上,压根没去心态写!!!),最后遗憾只拿省铜。
总的来说,这次比赛证明我的实践能力太弱,主要的锅在我身上,没有一眼看出M是个二分,总想贪心猜结论(被M卡了两个多小时)而且没有及时弃题去写L的dp跟H的模拟。队伍之间的配合也太少,应该在一起多讨论讨论,商量分工。
一开始跟队友分别找题,本来想先写b题,但两分钟看榜单有人把f题过了,于是我们就先去写了f
签到题,就照着题意去判断就能ac
#include<bits/stdc++.h>
using namespace std;
#define int long long
typedef pair<int,int> pii;
void solve()
{
int n;cin>>n;
int ans=0;
for(int i=0;i<n;i++)
{
string s;cin>>s;
if(s.size()==5&&set(s.begin(),s.begin()+4).size()==4&&s[2]==s[4])
ans++;
}
cout<<ans;
}
signed main()
{
ios::sync_with_stdio(false);
cin.tie(nullptr),cout.tie(nullptr);
int t=1;
//cin>>t;
while(t--)solve();
return 0;
}
写完签到题,我们又继续写b题,一开始想到这题类似于acwing里面的股票购买类型的题,那道题有dp和贪心两种解法,这题本来一开始也想写个dp,但是发现初状态并不好表示,于是写的是贪心解法,先写一个关于c[i]的后缀min,把金币留给后面小的花费时再购买。
#include<bits/stdc++.h>
using namespace std;
#define int long long
typedef pair<int,int> pii;
void solve()
{
int n;cin>>n;
vector<int>c(n);
for(int i=0;i<n;i++)cin>>c[i];
for(int i=n-2;i>=0;i--)
{
c[i]=min(c[i],c[i+1]);
}
int cnt=0;
int ans=0;
for(int i=0;i<n;i++)
{
cnt++;
if(cnt>=c[i])
{
cnt-=c[i];
ans++;
}
}
cout<<ans;
}
signed main()
{
ios::sync_with_stdio(false);
cin.tie(nullptr),cout.tie(nullptr);
int t=1;
//cin>>t;
while(t--)solve();
return 0;
}
后面看j题过的人数也比较多,我们跟榜做题。这题本来看只有五位数,想while_nextpermutation()直接暴力跑完的,但是发现了对于五位数有这样的性质:只要存在0,2,4,6,8,5这六个数字其中之一,把其放在末尾的位置,必定就是合数,而剩下的1,3,7,9只有四位数字,不够组成五位数,所以至少有0,2,4,6,8,5这六个数其中之一,因此这道题不存在-1这种情况,有了换位置的思路,只需要处理一下前导零就行了,方法也比较简单,判断换位后的s[0]是否为0,是则swap(s[0],s[1])就可以了。
#include<bits/stdc++.h>
using namespace std;
#define int long long
typedef pair<int,int> pii;
void solve()
{
string s;cin>>s;
int pos=0;
string ans="";
for(int i=0;i<s.size();i++)
{
if(s[i]=='0'||s[i]=='2'||s[i]=='4'||s[i]=='6'||s[i]=='8'||s[i]=='5')
{
pos=i;
break;
}
}
for(int i=0;i<s.size();i++)
{
if(i!=pos)ans+=s[i];
}
ans+=s[pos];
if(ans[0]=='0')swap(ans[0],ans[1]);
cout<<ans<<"\n";
}
signed main()
{
ios::sync_with_stdio(false);
cin.tie(nullptr),cout.tie(nullptr);
int t=1;
cin>>t;
while(t--)solve();
return 0;
}
比赛时只ac了这三道题,M、H、Ldebug半天均未调试出来
M需要将每个a[i]变为x,并满足式子:|ai − x| ≤ k × bi
通过数学公式变换可以推出a[i]-k*b[i]<=x<=a[i]+k*b[i],k越大x的范围也越大,可以用二分来判断这个x的区间是否存在。
#include<bits/stdc++.h>
using namespace std;
#define int long long
typedef pair<int,int> pii;
const int N=3e5+10;
int a[N],b[N];
int n;
bool check(int k)
{
int l=-1e18,r=1e18;
for(int i=0;i<n;i++)
{
l=max(l,a[i]-k*b[i]);
r=min(r,a[i]+k*b[i]);
}
return l<=r;
}
void solve()
{
cin>>n;
for(int i=0;i<n;i++)cin>>a[i];
for(int i=0;i<n;i++)cin>>b[i];
int l=0,r=1e9;
while(l<r)
{
int mid=(l+r)>>1;
if(check(mid))r=mid;
else l=mid+1;
}
cout<<l<<"\n";
}
signed main()
{
ios::sync_with_stdio(false);
cin.tie(nullptr),cout.tie(nullptr);
int t=1;
cin>>t;
while(t--)solve();
return 0;
}
H题就是顺着模拟,遇到-1取出已经存入的最小值,并记录,后续的-1如果取出一个数比上次取出的数要小,直接输出0.
#include<bits/stdc++.h>
using namespace std;
#define int long long
typedef pair<int,int> pii;
const int N=2e5+10,mod=998244353;
int a[N*2];
int n;
int qmi(int a,int b)
{
int res=1;
while(b)
{
if(b&1)res=res*a%mod;
a=a*a%mod;
b>>=1;
}
return res;
}
void solve()
{
cin>>n;
for(int i=1;i<=n*2;i++)cin>>a[i];
priority_queue<int,vector<int>,greater<int>>q;
vector<int>mp(n+1,0);
int l=-1;
int ans=1;
for(int i=1;i<=n*2;i++)
{
if(a[i]!=-1)
{
if(a[i]<l)
{
cout<<0;
return;
}
else
{
q.push(a[i]);
mp[a[i]]++;
}
}
else
{
int tt=q.top();
l=max(l,tt);
ans=(ans%mod*mp[tt]%mod*qmi((int)q.size(),mod-2))%mod;
mp[tt]--;
q.pop();
}
}
cout<<ans;
}
signed main()
{
ios::sync_with_stdio(false);
cin.tie(nullptr),cout.tie(nullptr);
int t=1;
//cin>>t;
while(t--)solve();
return 0;
}
L题,线性dp,dp[i]为解决了前i行bug的最少时间,状态转移方程为dp[a[i]]=min(dp[a[i]],dp[a[j]]+(i-j)*(i-j)*(i-j)*(i-j)+a[i])。
#include<bits/stdc++.h>
using namespace std;
#define int long long
typedef pair<int,int> pii;
const int N=2e5+10;
int a[N],dp[N];
int n,m;
void solve()
{
cin>>n>>m;
for(int i=1;i<=m;i++)cin>>a[i];
memset(dp,0x7f,sizeof dp);
dp[0]=0;
for(int i=1;i<=m;i++)
{
for(int j=i-1;j>=max(0LL,i-(int)sqrt(n));j--)
{
dp[a[i]]=min(dp[a[i]],dp[a[j]]+(i-j)*(i-j)*(i-j)*(i-j)+a[i]);
}
}
cout<<dp[a[m]];
}
signed main()
{
ios::sync_with_stdio(false);
cin.tie(nullptr),cout.tie(nullptr);
int t=1;
//cin>>t;
while(t--)solve();
return 0;
}