3.11-3.24周报
寒假训练营2#
D#
这道题的题意很简单,有k张技能牌,每张技能牌可以把前
点击查看代码
void solve(long long kk) {
priority_queue<PII,vector<PII>,greater<PII>>q;
int n,m,k;
cin>>n>>m>>k;
for(int i=1;i<=m;i++){
cin>>a[i]>>b[i];
}
for(int i=1;i<=n;i++){
dist[i]=LLONG_MAX;
}
dist[k]=0;
q.push({0,k});
while(q.size()){
auto [dis,dian]=q.top();
q.pop();
if(dist[dian]<dis)
continue;
for(int i=1;i<=m;i++){
int jl=a[i],hf=b[i];
jl+=dian;
jl%=n;
if(jl==0)
jl=n;
if(dist[jl]>hf+dis){
dist[jl]=hf+dis;
q.push({dist[jl],jl});
}
}
}
if(dist[n]==LLONG_MAX)
cout<<-1<<endl;
else
cout<<dist[n]<<endl;
return ;
}
codeforces 933 (Div.3)#
E#
这道题的题意很简单,就是每个位置的水深已知,要在两岸之间建桥,那就需要在一些位置建桥柱,桥柱之间的距离不得超过d,要连续建造k座桥,赛时没出也是因为没注意连续。一眼dp但是要注意不能直接暴力求,会超时,但我们发现,每个位置存的花费其实就是前d个里花费最小的和这个点建桥就可以了,那就不用暴力循环,直接求最小。
点击查看代码
void solve() {
ve.clear();
int n,m,K,d;
cin>>n>>m>>K>>d;
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
cin>>a[i][j];
}
}
for(int i=1;i<=n;i++){
//memset(dp,0x3f,sizeof(dp));
multiset<int>s;
dp[1]=1;
s.insert(dp[1]);
for(int j=2;j<=m;j++){
dp[j]=*(s.begin())+a[i][j]+1;
//cout<<j<<" "<<j-d-1<<" "<<*s.begin()<<" "<<dp[j]<<endl;
if(j-d-1>0){
s.erase(s.find(dp[j-d-1]));
}
s.insert(dp[j]);
// for(int k=j-1;k>0;k--){
// if(j-k-1>d){
// break;
// }
// dp[j]=min(dp[j],dp[k]+a[i][j]+1);
// }
}
//dp[m]=*s.begin()+a[i][m]+1;
ve.push_back(dp[m]);
//cout<<i<<" "<<dp[m]<<endl;
//cout<<"--------------\n";
}
long long cur = 0;
for (int i = 0; i < K; i++)
cur += ve[i];
long long mn = cur;
for (int i = K; i < n; i++) {
cur += ve[i] - ve[i - K];
mn = min(cur, mn);
}
cout << mn << endl;
return ;
}
天梯1#
7-6#
这题巨简单,但是问题出在了vector的size函数,这个函数的返回值不是int类型,所以要注意可能会出现x<ve.size()-1和x<=ve.size()两个公式不等价的情况。
7-11#
这道题大一就做过,当时就没认真补题,现在遇到还是没思路,其实很简单,根据题意可知,这一定是树,也就是跑完树上的几个点之后不用返回起点,那想要最短路就是遍历所有路径之后减去最长的那条路。找最深的结点就是个dfs,那怎么计算出跑完所有点的路径和呢,那就是返回到当前点回到根节点的路径还有多少路径是没有走过的(因为之前的点可能被其他的点走过了,那就不用重复走了)。
点击查看代码
int fa[100010];
int vis[100010];
vector<int>g[100010];
int dp[100010];
void dfs(int x){
for(auto e:g[x]){
dp[e]=dp[x]+1;
dfs(e);
}
}
void solve(long long kk) {
int n,m;
cin>>n>>m;
int root;
for(int i=1;i<=n;i++){
cin>>fa[i];
if(fa[i]==-1){
root=i;
}
else
g[fa[i]].push_back(i);
}
dp[root]=0;
dfs(root);
int max1=0;
int sum=0;
for(int i=1;i<=m;i++){
int x;
cin>>x;
max1=max(max1,dp[x]);
while(vis[x]==0&&x!=root){
vis[x]=1;
sum+=2;
x=fa[x];
}
cout<<sum-max1<<endl;
}
return ;
}
7-12#
这个题其实不难,就是一直不停的套map,因为这个明显也是树,但是可以优化的点是那些老人一定为叶子结点,那我们直接将一个管理机构下的老人数记作这个点的权值,在老人更换机构时就不用考虑边的问题了,直接更换双方的权值即可,求一个管理机构下的老人总数,就是以它为根节点的dfs搜索,权值求和就好,但是有一个段错误,不太懂问题在哪。
点击查看代码
map<pair<string,string>,int>d;
map<string,string>fa;
map<string,vector<string>>ve;
map<string ,int>xx;
int dfs(string s){
int ans=xx[s];
for(auto e:ve[s]){
ans+=dfs(e);
//cout<<e<<" "<<s<<" "<<ans<<endl;
}
return ans;
}
void solve(long long kk) {
int n,m;
cin>>n>>m;
for(int i=1;i<=m;i++){
string s1,s2;
cin>>s1>>s2;
fa[s1]=s2;
ve[s2].push_back(s1);
if(s1[0]>='0'&&s1[0]<='9')
xx[s2]++;
// cout<<i<<" "<<s2<<" "<<xx[s2]<<endl;
// for(auto e:ve[s2]){
// cout<<e<<" ";
// }
// cout<<"-----\n";
//fa[s1]=s2;
}
while(1){
string s1;
cin>>s1;
if(s1=="E"){
break;
}
if(s1=="T"){
string s2,s3;
cin>>s2>>s3;
string ss=fa[s2];
xx[ss]--;
//cout<<ss<<" "<<s2<<" "<<s3<<endl;
ve[s3].push_back(s2);
fa[s2]=s3;
xx[s3]++;
}
else if(s1=="Q"){
string s2;
cin>>s2;
int ans=0;
ans=dfs(s2);
cout<<ans<<endl;
}
}
return ;
}
codeforces 934(Div.2)#
B#
这道题题意很简单,就是把2n个数字(而且是1-n每个数字出现两次)左边一半右边一半,每一半都选k个,要求两边的异或值相同,异或有个规律两个相同的数字异或为0,那就很简单了,先选择出现两次的数字,保证异或值为0,不够就拿只出现一次的数字,只要是出现一次的数字那就是两边都会出现一次,那就都选,异或值还一样,但我细节敲错了,wa了好多次。
点击查看代码
int a[100010],b[100010];
set<int>s,sa,sb;
void solve() {
s.clear();
sa.clear();
sb.clear();
int n,k;
cin>>n>>k;
for(int i=1;i<=n;i++){
cin>>a[i];
sa.insert(a[i]);
}
for(int i=1;i<=n;i++){
cin>>b[i];
if(sa.count(b[i])){
s.insert(b[i]);
sa.erase(b[i]);
}
else{
sb.insert(b[i]);
}
}
if(sa.size()>=k){
int dans=0;
for(auto e:sa){
dans++;
cout<<e<<" "<<e<<" ";
if(dans==k){
break;
}
}
cout<<endl;
dans=0;
for(auto e:sb){
dans++;
cout<<e<<" "<<e<<" ";
if(dans==k){
break;
}
}
cout<<endl;
}
else {
int x=sa.size();
k -= x;
for (auto e: sa) {
cout << e << " " << e << " ";
}
int dans = 0;
for (auto e: s) {
cout << e << " ";
dans++;
if (dans == 2*k)
break;
}
cout << endl;
for (auto e: sb) {
cout << e << " " << e << " ";
}
dans = 0;
for (auto e: s) {
cout << e << " ";
dans++;
if (dans == 2*k)
break;
}
cout << endl;
}
return ;
}
天梯训练赛#
I#
这道题就是格雷码的生成,规律很简单,二倍延伸时后一半和前一半轴对称,后一半前一位补1,前一半的前一位补0,然后输出第几个是多少,这个题注意范围很大,要用unsigned long long,要注意后一半的时候因为是反过来的,所以要计算一下它是第几个。
点击查看代码
#define int unsigned long long
#define endl "\n"
vector<int>ve;
void solve() {
int n,k;
cin>>n>>k;
int d=pow(2,n-1);
//cout<<d<<endl;
string s;
for(int i=1;i<=n;i++){
//cout<<k<<" "<<d<<endl;
if(k>=d){
//cout<<k<<" "<<d<<endl;
s=s+'1';
k=d-(k-d+1);
}
else{
s=s+'0';
}
d/=2;
}
cout<<s<<endl;
return ;
}
J#
这道题已知每个队的实力和初始得分,按照得分排序,12 34 56这样比赛,比完之后实力值更高的得分+1,一看就是结构体排序,但是tle,我们可以注意,每次组好队之后,一定有n/2个队不得分,他们的相对位置不变,胜的同理,这是有顺序的排序,快排会非常浪费,应该使用归并排序,但是要注意,第一次要快排。
点击查看代码
struct node{
int cj, sl, id;
}a[200010],w[200010],l[200010];
bool cmp(node x,node y){
if(x.cj==y.cj){
return x.id<y.id;
}
return x.cj>y.cj;
}
void solve(long long kk) {
int n,r,q;
cin>>n>>r>>q;
for(int i=1;i<=2*n;i++){
cin>>a[i].cj;
a[i].id=i;
}
for(int i=1;i<=2*n;i++){
cin>>a[i].sl;
}
sort(a+1,a+1+2*n,cmp);
for(int i=1;i<=r;i++){
int lose=0,win=0;
for(int j=1;j<=2*n;j+=2){
if(a[j].sl>a[j+1].sl){
a[j].cj++;
w[++win]=a[j];
l[++lose]=a[j+1];
}
else{
a[j+1].cj++;
w[++win]=a[j+1];
l[++lose]=a[j];
}
}
merge(w+1,w+1+n,l+1,l+1+n,a+1,cmp);
}
cout<<a[q].id<<endl;
return ;
}
Codeforces 935(Div.2)#
D#
这个题蛮好玩的,就是插队,如果你要插某人的队,那你要给它a的钱,从你到这个人之间的所有人你都要给b的钱,其实就是个贪心,但是要注意,到达m之前的位置,不是必须到m
点击查看代码
int a[200010],b[200010];
void solve() {
int n,m;
cin>>n>>m;
for(int i=1;i<=n;i++){
cin>>a[i];
}
for(int i=1;i<=n;i++){
cin>>b[i];
}
int sum=0;
for(int i=n;i>m;i--){
sum+=min(a[i],b[i]);
}
int sum1=0,min1=LLONG_MAX;
for(int i=m;i>0;i--){
min1=min(min1,a[i]+sum1);
sum1+=min(a[i],b[i]);
}
sum+=min1;
cout<<sum<<endl;
return ;
}
E#
这道题题面就是一个二分查找,按照题意的查找方法写二分很快,但有一个点是没有排序,你最多对现有的顺序进行两次交换,使得不按顺序排序的二分查找依然可以找到这个数。当时就有个想法是先看看不交换的话能找到哪个数,然后直接把这两个数交换,其实没想通为什么,但是想试一下就这么写了一下,还真过了。
点击查看代码
#include <bits/stdc++.h>
#define int long long
#define endl '\n'
using namespace std;
int a[200010],b[200010];
void solve() {
int n,x;
cin>>n>>x;
int d;
for(int i=1;i<=n;i++){
cin>>a[i];
if(a[i]==x){
d=i;
}
}
int l=1,r=n+1,mid;
while(r-l!=1){
mid=(l+r)/2;
if(a[mid]<=x){
l=mid;
}
else{
r=mid;
}
}
if(d==l){
cout<<"0\n";
return ;
}
cout<<1<<"\n";
cout<<d<<" "<<l<<endl;
return ;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
· 25岁的心里话