Hello 2026练习
Hello 2026练习
B - Yet Another MEX Problem
观察一下样例就能够发现其实答案就是整个数组的mex和k-1取min,但是一开始写这个题目的时候多虑了要去重,就当是练习去重好了
void solve(){
int n,k;
cin>>n>>k;
vi a(n);
for(int i=0;i<n;i++) cin>>a[i];
sort(a.begin(),a.end());
auto last=unique(a.begin(),a.end());
a.erase(last,a.end());
int l=0;
for(int i=0;i<min((int)a.size(),k-1);i++){
if(a[i]==l) l++;
}
cout<<l<<endl;
}
C - War Strategy
这个题目如果你考虑在一端开始进行士兵的部署的话答案是2*k-1(如果部署不包括大本营所在的k格),但是如果考虑两边的话就有更优的选择了,所以我们暂且设置为左边更优,两边同时部署,左边比右边优了就部署右边,如果部署的总日期小于m了就直接结束循环
void solve(){
int n,m,k;
cin>>n>>m>>k;
if(k-1<n-k) k=n-k+1;
int l=0,r=0;
while(1){
if(r<n-k&&l+r+1+max(l,r+1)-1<=m) r++;
if(l<k-1&&l+1+r+max(l+1,r)-1<=m) l++;
else break;
}
cout<<l+r+1<<endl;
}
D1 - Tree Coloring (Easy Version)
简单版的时候直接考虑对每层的点数目取min即可,又因为相邻边的不能是同样的颜色,所以还要加上这一层节点的父亲对 邻接+本身点数目 进行考虑
vi g[N];
int d[N];
int ans;
void dfs(int u,int fa){
for(int v:g[u]) if(v!=fa) d[v]=d[u]+1,dfs(v,u);
}
void solve(){
ans=0;
int n;
cin>>n;
for(int i=0;i<=n;i++) g[i].clear();
for(int i=0;i<n-1;i++){
int x,y;
cin>>x>>y;
g[x].pb(y);
g[y].pb(x);
}
dfs(1,0);
vi num(n);
for(int i=1;i<=n;i++) num[d[i]]++;
for(int i=0;i<n;i++) ans=max(ans,num[i]);
ans=max((int)g[1].size()+1,ans);
for(int i=2;i<=n;i++){
ans=max((int)g[i].size(),ans);
}
cout<<ans<<endl;
}
D2 - Tree Coloring (Hard Version)
如果要落实到分配的方法的话 答案和方法都不唯一,这里采取的是先dfs一遍得到所有点的深度和父亲,接着对于每一层把父子连成pair,交错放入两个相邻的集合,如果这样放完之后同层还有点没有放入集合的话就单独在已有的集合里面扫一遍,如果已有集合里点数同层或者边有邻接就不选
vector<int>g[N];
int d[N],fa[N],id[N];
int ans;
void dfs(int u,int f){
fa[u]=f;d[u]=d[f]+1;
for(int v:g[u]) if(v!=f) dfs(v,u);
}
vi vec[N];
void solve(){
ans=0;
int n;
cin>>n;
for(int i=0;i<=n;i++) g[i].clear(),vec[i].clear();
for(int i=0;i<n-1;i++){
int x,y;
cin>>x>>y;
g[x].pb(y);
g[y].pb(x);
}
dfs(1,0);
vector<vi> ans;
//d[i]记录每个点的深度,vec[i]记录的是深度为i的点的集合
for(int i=1;i<=n;i++) vec[d[i]].pb(i),id[i]=-1;
ans.pb({1});id[1]=0;
for(int i=2;i<=n;i++){
vector<pii> vv;
for(int x:vec[i-1]){
int son=0;
for(int y:g[x]) if(y!=fa[x]){ son=y;break;}
//
if(son) vv.emplace_back(x,son);
}
if(vv.size()>1){
for(int i=0;i<vv.size();i++){
int nxt=(i+1)%vv.size();
ans[id[vv[nxt].fi]].pb(vv[i].se);
id[vv[i].se]=id[vv[nxt].first];
}//刚好交错着放一下
}
int now=0;
for(int x:vec[i]) if(id[x]<0){//分配这一层 还没有被分配到集合里面 的点
while(now<ans.size()&&(d[ans[now].back()]==i||ans[now].back()==fa[x])) now++;
if(now==ans.size()) ans.pb({x});
else ans[now].pb(x);
id[x]=now;
}
}
cout<<ans.size()<<endl;
for(auto vv:ans){
cout<<vv.size();
for(int i:vv) cout<<' '<<i;
cout<<endl;
}
E - LCM is Legendary Counting Master
这里的必要转换就是lcm(x,y)=x*y/gcd(x,y),所以倒数就是gcd(x,y)/x*y,gcd(x,y)<=(x-y),所以放缩之后就可以转换为1/a1<=1,所以可以用a1进行特判,因为右边的不等式取等的充要条件是gcd(x,y)=(x-y),所以直接对第一次放缩后的式子进行递推/dp即可,记得预处理一下因子
int dp[3005][3005];
vi d[3005];
void solve(){
int n,m;
cin>>n>>m;
vi a(n+1);
for(int i=1;i<=n;i++) cin>>a[i];
if(a[1]>1){cout<<"0\n";return ;}
for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) dp[i][j]=0;
dp[1][1]=1;
for(int i=2;i<=n;i++){
for(int j=1;j<=m;j++){
if(dp[i-1][j]){
for(int v:d[j]){
if((a[i]==j+v||a[i]==0)&&j+v<=m) dp[i][j+v]=(dp[i-1][j]+dp[i][j+v])%MOD;
}
}
}
}
int ans=0;
for(int i=1;i<=m;i++) ans=(ans+dp[n][i])%MOD;
cout<<ans<<endl;
}
signed main(){
ios::sync_with_stdio(false);
cin.tie(0);
for(int i=1;i<=3000;i++){
for(int j=i;j<=3000-i;j+=i){
d[j].pb(i);//预处理找所有的因子
}
}
int T=1;
cin>>T;
while(T--)
solve();
return 0;
}
模板看来还是得改改~~~~~~~~~~

浙公网安备 33010602011771号