2023河南CCPC省赛vp部分补题
A 模拟 暴力
对每个合法的前缀,判断后缀是不是合法
int a[29];
void solve(){string s;cin>>s;int t=-1;if(s.size()==1){return cout<<"NaN"<<endl,void();}for(int i=0;i<=27;i++) a[i]=0;for(int i=0;i<s.size();i++){a[s[i]-'a']++;if(a[s[i]-'a']>1){t=i;break;}else{string ss=s.substr(i,s.size()-i);string s1=ss;reverse(ss.begin(),ss.end());if(ss==s1){return cout<<"HE"<<endl,void();}else continue;}}if(t==-1)t=s.size()-1;if(t==s.size()-1){return cout<<"HE"<<endl,void();}string ss=s.substr(t,s.size()-t);string s1=ss;reverse(ss.begin(),ss.end());if(ss==s1) cout<<"HE"<<endl;else cout<<"NaN"<<endl;
}
B 思维 枚举
题意:每k个数一组,每小组升序排序后能让整个排序变成升序
思路:
- 若要满足题意,那么每个组的最大值要小于等于下一组的最小值,就是前缀最大值小于等于下一个数的后缀最小值,这就是组和组的边界
- 标记每一个边界位置,枚举k,找符合题意的k的个数
void solve()
{int n;cin>>n;vector<int>a(n+1),pmax(n+1,0),smin(n+2,1e9);forr(i,1,n){cin>>a[i];}reforr(i,1,n){smin[i]=min(smin[i+1],a[i]);}vector<int>rec(n+1,0);forr(i,1,n){pmax[i]=max(pmax[i-1],a[i]);if(pmax[i]<=smin[i+1])rec[i]=1;}//nlognint ans=0;forr(k,1,n){ans++;// cout<<k<<' ';for(int i=k;i<=n;i+=k){//这里的复杂度是lognif(rec[i]==0){ans--;// cout<<-1;break;}}// cout<<endl;}cout<<ans<<endl;// forr(i,1,n)cout<<pmax[i]<<' ';// cout<<endl;// forr(i,1,n)cout<<smin[i]<<' ';// cout<<endl;
}
/*
6
4 1 3 5 2 6
2
*/
E 三维dp 滚动数组
const int N=510,K=1e3+10;
string mp[N];
//空间优化 滚动数组
//要从上面一行转移过来,存两行,奇数行1偶数行0
int dp[2][N][K];
void solve()
{int n,m,x;cin>>n>>m>>x;forr(i,0,m){forr(j,0,x){dp[0][i][j]=dp[1][i][j]=0;}}forr(i,1,n){cin>>mp[i];mp[i]='0'+mp[i];}forr(i,1,n){forr(j,1,m){forr(k,0,x){if(mp[i][j]=='1')dp[i&1][j][k]=max(dp[i&1][j-1][k],dp[(i-1)&1][j][k])+1;else if(mp[i][j]=='0') dp[i&1][j][k]=max(dp[i&1][j-1][k],dp[(i-1)&1][j][k]);else{//?if(k>=1)dp[i&1][j][k]=max(dp[i&1][j-1][k-1],dp[(i-1)&1][j][k-1])+1;//?尽量变成1else dp[i&1][j][0]=max(dp[i&1][j-1][0],dp[(i-1)&1][j][0]);//没有k=-1的状态 原地tp}}}}int ans=dp[n&1][m][0];forr(i,1,x){ans=max(ans,dp[n&1][m][i]);}cout<<ans<<endl;
}
F 排序
题意:让min和max尽量小。排序后,min是相邻数之间的值差,max是隔k-2个数的两值之差
vp时对怎么找k-1个值差的最小值有点犯难,枚举判断必超时,一开始想写纯双指针,但是维护最小值太麻烦,于是选择了傻瓜式的multi_set
void solve()
{int n,k;cin>>n>>k;vector<int>a(n+1),mind(n),maxd(n);forr(i,1,n)cin>>a[i];sort(a.begin()+1,a.end());forr(i,1,n-1){mind[i]=a[i+1]-a[i];// cout<<mind[i]<<' ';}//cout<<endl;int l=1,r=k-1;multiset<int>s;forr(i,1,k-1)s.insert(mind[i]);int ans=1e18+100;forr(i,1,n-k+1){int minn=(*s.begin());maxd[i]=a[i+k-1]-a[i];ans=min(maxd[i]*minn,ans);r++;if(r>=n)break;auto tp=s.lower_bound(mind[l]);//有序数组二分找要扔掉的值s.erase(tp);s.insert(mind[r]);l++;}cout<<ans<<endl;
}
/*
13 7
1 1 4 5 1 4 1 9 1 9 8 1 04 2114 514 1919 8106 3121 117 114 105 107 111
*/
H 贪心
题意:取的数个数相等,为k,让取的每个数四舍五入后尽量小/大
- min:尽量四舍
- 任何小数部分<0.5的数都可舍去,策略可以是每次分出 0.5 − δ 0.5-\delta 0.5−δ,分k-1个
- 剩下的数也要尽量小,取得 0.5 − δ 0.5-\delta 0.5−δ尽量大,那么 δ → 0 , 1 e 9 ⋅ δ → 0 \delta\rightarrow 0,1e9\cdot\delta \rightarrow 0 δ→0,1e9⋅δ→0,无穷小忽略,就是每次分出0.5,分k-1次剩下的取round
- max:五入
- 能五入的最小是0.5,让剩下的一个数尽量大,其他k-1个数就得取0.5
void solve()
{int n,k;cin>>n>>k;double rst1=1.0*n-(k-1)*0.5;int minn=round(rst1);minn=max(minn,0ll);double rst=1.0*n-(k-1)/2;int maxn=round(rst)+k-1;maxn=min(2*n,maxn);cout<<minn<<' '<<maxn<<endl;
}
K 构造
题意:形成一个环,环之间的差值是质数
- 质数:2,3,5,7,11,13…大部分是奇数
- 枚举得到n<=4,输出-1
- 相邻奇/偶数之间的差是2,奇偶之间的差值是奇数,所以可以分奇偶进行构造
belike(n为偶数) 1,3,5,7,…,n-3,n-1,n,n-2,6,4,2 但是2和n-1放错了位置,重新放
2在5和7之间必然合法
n-1在n-4和n-6之间必然合法(差是3,5)
但是应该n-4!=7,并且n应该>6
而且n-1!=7,让5和7位置固定 - 枚举5~10的答案,更大的n分奇偶进行构造
void solve()
{//分奇偶int n;cin>>n;if(n<=4)return cout<<-1<<endl,void();switch (n){case 5:cout<<"4 1 3 5 2"<<endl;break;case 6:cout<<"4 6 1 3 5 2"<<endl;break;case 7:cout<<"4 6 1 3 5 7 2"<<endl;break;case 8:cout<<"4 6 8 1 3 5 7 2"<<endl;break;case 9:cout<<"4 9 6 8 1 3 5 7 2"<<endl;break;case 10:cout<<"4 9 6 8 1 3 10 5 7 2"<<endl;break;case 11:cout<<"4 9 6 11 8 1 3 10 5 7 2"<<endl;break;default:{vector<int>ans;if(n&1){//奇数for(int i=1;i<=n-2;i+=2){ans.push_back(i);if(i==5)ans.push_back(2);if(i==n-6)ans.push_back(n-1);}ans.push_back(n);for(int i=n-3;i>=4;i-=2){ans.push_back(i);}}else{//偶数for(int i=4;i<=n-2;i+=2){ans.push_back(i);if(i==n-6)ans.push_back(n-1);}ans.push_back(n);for(int i=n-3;i>=1;i-=2){ans.push_back(i);if(i==7)ans.push_back(2);}}for(auto i:ans)cout<<i<<' ';cout<<endl;}}
}