2023 Hubei Provincial Collegiate Programming Contest Finished
2023 Hubei Provincial Collegiate Programming Contest
C - Darkness I
思路:对于n,m相同的情况,最小的是取对角线上的格子,为min(n,m);对于n,m不相同的情况,最小的是先取可形成的最大的正方形,为min(n,m),对于剩余的abs(n-m)行/列,最小的情况是每隔一行/列取一个,并且最右边一定取一个,判断下奇偶即可
#include<bits/stdc++.h> using namespace std; typedef pair<int,int>PII; typedef pair<string,int>PSI; const int N=2e5+5,INF=0x3f3f3f3f,Mod=1e9+7; const double eps=1e-6; typedef long long ll; int n,m; int main(){ ios::sync_with_stdio(0),cin.tie(0),cout.tie(0); cin>>n>>m; int res; if(n==1||m==1){ int s=max(n,m); res=s/2+1; }else{ res=min(n,m); int s=max(m,n)-min(n,m); res+=s/2; if(s%2)res++; } cout<<res; return 0; }
F - Inverse Manacher
思路:由于只含字符a和b,固定第一个字符,判断每个 “|”的半径,若为1,则下一个字符与前一个字符不同,否则相同
#include<bits/stdc++.h> using namespace std; typedef pair<int,int>PII; typedef pair<string,int>PSI; const int N=1e5+5,INF=0x3f3f3f3f,Mod=1e9+7; const double eps=1e-6; typedef long long ll; int n; int main(){ ios::sync_with_stdio(0),cin.tie(0),cout.tie(0); cin>>n; string s="a"; for(int i=1,x;i<=2*n+2;++i){ cin>>x; if(i>=4&&i%2==0&&i<2*n+2){ char c=s[s.size()-1],y; if(x==1){ if(c=='a')y='b'; else y='a'; } else { if(c=='a')y='a'; else y='b'; } s+=y; } } cout<<s; return 0; }
H - Binary Craziness
思路:入度范围为2m,入度种数范围为√ 2m,统计所有种数个数,暴力枚举每两种入度的 f 乘上 个数积
#include<bits/stdc++.h> using namespace std; #define int long long int du[1000006]; int g[2000006]; const int mod=998244353; signed main(){ ios::sync_with_stdio(false),cin.tie(0); cout.tie(0); int n,m; cin>>n>>m; for (int i = 0; i <m ; ++i) { int x,y; cin>>x>>y; du[x]++,du[y]++; } for (int i = 1; i <=n ; ++i) { g[du[i]]++; } vector<pair<int,int>>f; for (int i =1; i <=2*m ; ++i) { if(g[i]>0){ f.push_back({i,g[i]}); } } int res=0; for (int i = 0; i <f.size() ; ++i) { for (int j = i+1; j <f.size() ; ++j) { res=(res+(f[i].second*f[j].second%mod*(f[i].first^f[j].first)*(f[i].first&f[j].first)*(f[i].first|f[j].first)))%mod; } } cout<<res<<endl; }
J - Expansion
思路:每一秒加的是所有开垦过的系数和,若满足开垦该块地后下一秒末的能源大于等于0则可开垦该块地;统计系数前缀和b[i],前缀最大值ma[i](第一个最大值);遍历b,当 b[i]+当前能源 小于0时,说明当前不满足开垦第i块地的情况,那就要在b[1~i-1]max中多停留 t 秒,增加的能源add为 t*b[1~i-1]max,使得b[i]+当前能源+add大于等于0,且b[1~i-1]max一定要大于0;最后最小时间即为所有多停留的时间加上n;
#include<bits/stdc++.h> using namespace std; typedef pair<int,int>PII; typedef pair<string,int>PSI; const int N=1e5+5,INF=0x3f3f3f3f,Mod=1e9+7; const double eps=1e-6; typedef long long ll; typedef pair<ll,ll>PLL; int n; ll a[N],b[N]; ll ma[N]; int main(){ ios::sync_with_stdio(0),cin.tie(0),cout.tie(0); cin>>n; for(int i=1;i<=n;++i){ cin>>a[i],b[i]=b[i-1]+a[i]; ma[i]=max(b[i],ma[i-1]); } if(b[n]<0||b[1]<0)cout<<"-1"; else{ ll res=0,all=0,add=0; for(int i=1;i<=n;++i){ if(b[i]<0){ if(b[i]+all+add>=0){ all+=b[i]; continue; } ll s=-b[i],ss=ma[i]; s-=(all+add); if(ss<=0){ cout<<"-1"; return 0; } ll t=ceil(1.0*s/ss); res+=t; add+=t*ss; } all+=b[i]; } res+=n; cout<<res; } return 0; }
K - Dice Game
思路:剩下的人的概率都相同,当为xi时,对于一个人来说,第一次赢他的概率为(m-x)/m,第j次赢他的概率为(m-x)/mj,总概率为
(m-x)*(1/m+1/m2+...+1/mj)=(m-x)(1-1/mj)/(m-1)=(m-x)/(m-1)
#include<bits/stdc++.h> using namespace std; typedef pair<int,int>PII; typedef pair<string,int>PSI; const int N=2e5+5,INF=0x3f3f3f3f,Mod=998244353; const double eps=1e-6; typedef long long ll; ll n,m; ll ksm(ll a,ll b){ ll res=1; while(b){ if(b&1)res=res*a%Mod; a=a*a%Mod; b>>=1; } return res%Mod; } int main(){ ios::sync_with_stdio(0),cin.tie(0),cout.tie(0); cin>>n>>m; for(int i=1;i<=m;++i){ ll res=ksm((m-i)*ksm(m-1,Mod-2)%Mod,n); cout<<res<<' '; } return 0; }
M - Different Billing
思路:暴力举出b,满足y=1000b+2500c且b+c小于等于x
#include<bits/stdc++.h> using namespace std; typedef pair<int,int>PII; typedef pair<string,int>PSI; const int N=2e5+5,INF=0x3f3f3f3f,Mod=998244353; const double eps=1e-6; typedef long long ll; int x,y; int main(){ ios::sync_with_stdio(0),cin.tie(0),cout.tie(0); cin>>x>>y; for(int i=0;i<=x;++i){ if((y-1000*i)%2500==0){ int c=(y-1000*i)/2500; if(c<=x-i){ cout<<x-i-c<<' '<<i<<' '<<c;return 0; } } } cout<<-1; return 0; }