您的位置:首页 > 汽车 > 时评 > CF刷题记录

CF刷题记录

2024/9/22 6:31:48 来源:https://blog.csdn.net/2301_79347603/article/details/142066066  浏览:    关键词:CF刷题记录

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档

CF刷题记录

  • cf969
    • c题
    • d题
    • e题
    • f题
  • cf967
    • c题
    • d题
  • cf965
    • b题
    • c题
    • d题
  • cf963
    • c题
    • d题
      • 求<x的数量
      • 求>=x的数量


cf969

c题

  • 题目描述:
    给定整数数组,和整数a,b(可相等),可以任意选择数组元素,进行加减a或b的操作,该操作任意次。输出数组最大值与最小值差的最小值。
  • 题解
    首先±a,b等价于加减gcd(a,b),设为d。且可以确定最后的数组极差不会大于d,故将数组元素先取MODd,然后将数组升序排序,得到的数组设为c。
    考虑每个元素都可能作为最小值,首先令 c 1 c_1 c1为最小值,则极差为 c n − 1 − c 1 c_{n-1}-c_1 cn1c1,然后从 c 2 c_2 c2开始遍历数组,当 c i c_i ci为最小值,那么最大值为 c i − 1 + d c_{i-1}+d ci1+d,极差为 c i − 1 + d − c i c_{i-1}+d-c_i ci1+dci,然后更新最小值。
#include <bits/stdc++.h>
using namespace std;
const int N = 1e5 + 2;
int n,a,b;
int gcd(int a,int b){return b==0 ? a : (gcd(b,a%b));
}
int c[N];
int main() {ios::sync_with_stdio(0);cin.tie(0);int t;cin >> t;while (t--) {cin>>n>>a>>b;int d=gcd(a,b);for(int i=0;i<n;i++){cin>>c[i];c[i]%=d;}sort(c,c+n);int ans=c[n-1]-c[0];for(int i=1;i<n;i++){ans=min(ans,c[i-1]+d-c[i]);}cout<<ans<<'\n';}return 0;
}

d题

  • 题目描述:
    一颗树,每个节点是1或0或?(表示未确定),对于一个叶子节点,从根节点到叶子节点形成01串,若01的数量和10的数量不同,则计一分,否则不计分。周sir和和他的小跟班玩游戏,每个人轮流将?确定为0或1,周sir需要得分越高越好,而小跟班希望越小越好,两个人都很聪明,周sir先手,输出最后的得分。
  • 题解
    我们发现一个01串是否几分只与根节点和叶子节点的值有关(若两者相同,怎不计分,反之计分),故有多种情况讨论
    我们定义几个数据,方便说明:cnt0:值为0的叶子数,cnt1:值为1的叶子数,cnt2:值为?的叶子数,cnt3:值为?的非根非叶子数。
    1.根节点确定。假设为1,那么答案为cnt0+(cnt2+1)/2
    2.根节点为?。若cnt0>cnt1,则周sir第一步令根节点为1。之后依次确定根节点,则答案为cnt0+cnt2/2,反之就不赘述了
    3.根节点为?且cnt0==cnt1,此时先确定根节点是不明智的选择,周sir只能用cnt3来拖延时间,若cnt3为奇数,则是轮到小跟班确定根节点,那么答案为cnt0+(cnt2+1)/2;若cnt3为偶,答案为cnt0+cnt2/2;
#include <bits/stdc++.h>
using namespace std;
const int N = 1e5 + 2;
int n,a,b;
string s;
int cnt[N];
int main() {ios::sync_with_stdio(0);cin.tie(0);int t;cin >> t;while (t--) {memset(cnt,0,sizeof cnt);cin>>n;for(int i=1;i<n;i++){cin>>a>>b;cnt[a]++,cnt[b]++;}cin>>s;int cnt0=0,cnt1=0,cnt2=0,cnt3=0;for(int i=1;i<n;i++){if(cnt[i+1]==1){if(s[i]=='1'){cnt1++;}else if(s[i]=='0'){cnt0++;}}if(s[i]=='?'){if(cnt[i+1]==1)cnt2++;else cnt3++;}}if(s[0]!='?'){if(s[0]=='1'){cout<<cnt0+(cnt2+1)/2<<'\n';}else{cout<<cnt1+(cnt2+1)/2<<'\n';}}else{if(cnt1>cnt0){cout<<cnt1+cnt2/2<<'\n';}else if(cnt1<cnt0){cout<<cnt0+cnt2/2<<'\n';}else{if(cnt3&1){cout<<cnt1+(cnt2+1)/2<<'\n';}else{cout<<cnt1+cnt2/2<<'\n';}}}}return 0;
}

e题

放弃,题解都看不懂

f题

放弃

cf967

c题

交互题

  • 题目描述:
    告诉你树有n个节点,允许你询问15n次最多,每次询问格式为"? a b",系统返回给你使d(x,a)-d(x,b)的最小的x,若有多个,返回d(x,a)最小的那个。最后输出n-1条边,以!开头。
  • 题解
    树的每一个节点都可以是根,所以不妨设1节点为根,遍历i从2~n,在1和i之间二分直到,中点等于起点,就得到了i的父节点。
#include <bits/stdc++.h>
using namespace std;
const int N = 3e5+2;
int n,ans;
int a[N];
int b[N];
int now=0;
int main() {int t;cin >> t;while (t--) {now=0;cin>>n;for(int i=2;i<=n;i++){cout<<"? "<<1<<' '<<i<<'\n';cin>>ans;int u=1,v=i;while(ans!=u){u=ans;cout<<"? "<<u<<' '<<i<<'\n';cin>>ans;}a[now]=u;b[now]=v;now++;}cout<<"! ";for(int i=0;i<now;i++){cout<<a[i]<<" "<<b[i]<<" ";}cout<<'\n';}return 0;
}

d题

不敢恭维

cf965

b题

1000分的题卡住了,蚌埠住了

  • 题目描述
    给你一个由1~n的数字组成的排列a,请输出另一种排列p,使
    a i + . . . a j = = p i + . . . + p j a_i+...a_j==p_i+...+p_j ai+...aj==pi+...+pj的区间数量最少。
  • 题解
    其实就是将a全体循环向右移动一位。
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 2e5 + 2;
int n,a[N];
int main(){int t;cin>>t;while(t--){cin>>n;for(int i=1;i<=n;i++)cin>>a[i];cout<<a[n]<<' ';for(int i=1;i<n;i++)cout<<a[i]<<' ';cout<<'\n';}return 0;
}

c题

  • 题目描述
    给定整数n,k,数组a,b。你可以使 b i b_i bi为1的 a i a_i ai增加,总共增加的大小不能大于k。求max( a i a_i ai+f( a i a_i ai)),其中f( a i a_i ai)为将 a i a_i ai去掉后的数组a’的中位数。
  • 题解
    根据贪心思想, a i a_i ai一定会选择最大的数(可能是最大的 b i b_i bi为0的数,也可能是最大的 b i b_i bi为1的数);
    分两种情况讨论,若 b i b_i bi为1,那么将k全加在 a i a_i ai上最佳。然后排序求个中位数。较为轻松。
    b i b_i bi为0,那么k就要分配给剩下的数,使得中位数最大化,我们考虑二分思想,从而得到最大化的中位数。
    最后取两种情况的max。
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 2e5 + 2;
ll n,k,ans,cnt;
struct node{ll da,b;
}a[N];
bool cmp(node a,node b){if(a.b==b.b)return a.da>b.da;return a.b<b.b;
}
bool check(ll x){int sum=0;for(int i=2;i<=cnt;i++){if(a[i].da>=x)sum++;}ll k1=k;for(int i=cnt+1;i<=n;i++){if(a[i].da>=x){sum++;}else if(a[i].b && k1>=x-a[i].da){sum++;k1-=x-a[i].da;}}return sum>=(n+1)/2;
}
int main(){int t;cin>>t;while(t--){cin>>n>>k;ans=0;cnt=0;for(int i=1;i<=n;i++)cin>>a[i].da;for(int i=1;i<=n;i++){cin>>a[i].b;if(a[i].b==0)cnt++;}sort(a+1,a+n+1,cmp);if(cnt){ll l=0,r=INT_MAX;while(l+1<r){ll mid=(r+l)>>1;if(check(mid))l=mid;else r=mid;}ans=max(ans,a[1].da+l);}if(cnt!=n){swap(a[cnt+1],a[n]);sort(a+1,a+n,[](node x,node y){return x.da<y.da;});ans=max(ans,a[n].da+k+a[n/2].da);}cout<<ans<<'\n';}return 0;
}

d题

  • 题目描述
    两只牛,一只叫Bessie,一只叫Elsie,有n个岛,编号为1~n,有n-1条主桥(且为单向桥),即i—(i+1),(1<=i<=n-1)。
    还有m条跳跃桥(同为单向桥)。
    Bessie只能走主桥,Elsie两种桥都能走,两个人比谁先到n号岛。Bessie先走,Elsie起点为1号岛。
    当一只牛从i岛去j岛,i岛坍塌。
    输出Bessie起点分别在1,2,…n-1号岛,能否胜利,能输出1,否输出0;

  • 题解
    dp
    dp[i]的Elsie的路线可以分为两种:
    1.路线的倒数第二个岛为i-1,枚举从i-1岛出发的跳跃桥。
    2.路线的倒数第二个岛不为i-1,这种情况的最优解为dp[i-1]-1;
    若dp[i]>0,代表Bessie会输

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 2e5 + 2;
int n,m;
int mem[N];//记录Elsie不受阻碍到达各点的最短时间
int dp[N];//记录B牛的起点为i时Elsie能够最多领先的时间
int u,v;
int main(){int t;cin>>t;while(t--){cin>>n>>m;vector<vector<int>>a1(n+1);//后面连接的alternative桥vector<vector<int>>a2(n+1);//前面连接的~~~for(int i=1;i<=m;i++){cin>>u>>v;a1[u].push_back(v);a2[v].push_back(u);}mem[1]=0;for(int i=2;i<=n;i++){mem[i]=mem[i-1]+1;for(auto x:a2[i]){mem[i]=min(mem[i],mem[x]+1);}}dp[1]=-1;cout<<"1";for(int i=2;i<=n-1;i++){dp[i]=dp[i-1]-1;for(auto x:a1[i-1]){dp[i]=max(dp[i],x-i-mem[i-1]-1);}if(dp[i]>0)cout<<"0";else cout<<"1";}cout<<"\n";}return 0;
}

cf963

c题

  • 题目描述
    n个房间, a i a_i ai表示第i个房间灯亮的时间,之后k秒后灯灭,再k秒后灯亮,如此进行下去;
    输出n个房间同时亮的最早时刻,若没有,输出-1;
  • 题解
    我们发现n个房间的状态具有周期性,为2k;
    故我们对 a i a_i ai取mod(2
    k),模数一样的可看作相同房间,并进行中心化:将最晚开始亮的房间的模数调整到k,方便后续操作,将调整后的数组,记录为b。
    我们考虑最晚开始亮的房间,例如 a 1 a_1 a1,那么我们只需要考察 a 1 a_1 a1 a 1 + k a_1+k a1+k这个时间段是否有同时亮的情况,我们发现同时亮的充分必要条件为 m a x ( b i ) − m i n ( b i ) max(b_i)-min(b_i) max(bi)min(bi)<k。且最早时刻为 a i + m a x ( b i ) − k a_i+max(b_i)-k ai+max(bi)k
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 2e5 + 2;
ll n,k;
ll m=0;//最晚的房间
ll a[N];
ll b1,b2;//b1:最小mod值,最大mod值
int main() {int t;cin >> t;while (t--) {m=0;cin>>n>>k;b1=k+1,b2=-1;ll nn=2*k;for(int i=1;i<=n;i++){cin>>a[i];m=max(m,a[i]);}ll tmp=k-m%nn;//中心化for(int i=1;i<=n;i++){ll x=(a[i]%nn+tmp+nn)%nn;b1=min(b1,x);b2=max(b2,x);}if(b2-b1<k){cout<<m+b2-k<<'\n';}else{cout<<"-1\n";}}
}

d题

  • 题目描述
    给定长度为n的整数数组a,给定k。若a的长度大于k,则选择数组中k个连续的数删去,直到a的长度不大于k停止删除。
    返回所有可能性中最终数组的中位数的最大值。
  • 题解
    设最终a的长度为tmp。
    考虑二分
    每次判断最终数组大于等于(或小于)mid的数量的最大值是否大于等于tmp/2+1(或小于(tmp+1)/2)。若是,l=mid;否则,r=mid;
    dp数组
    dp[i]代表从初始数组为 a 1 a_1 a1~ a i a_i ai的最终数组……
    dp2[i]有些许不同,它要求最终数组长度严格小于k。

两种思路:

求<x的数量

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 5e5 + 2;
int n,k;
ll dp[N],dp2[N];
int a[N];
int ans;
int rem(int a, int b) {if (a % b == 0)return b;return a % b;
}
bool check(int x){for (int i = 0; i <= n; i++)dp[i] = 0;for (int i = 1; i <= k; i++)dp[i] = dp[i - 1] + (a[i] < x);for (int i = 1; i <= k - 1; i++)dp2[i] = dp2[i - 1] + (a[i] < x);for (int i = k; i <= n; i++) {dp2[i] = dp2[i - 1] + (a[i] < x);dp2[i] = min(dp2[i], dp2[i - k]);}for (int i = k + 1; i <= n; i++) {dp[i] = dp2[i - 1] + (a[i] < x);dp[i] = min(dp[i], dp[i - k]);}//dp[n]个<x的,rem(n,k)-dp[n]个>=x的 return (rem(n, k) + 1) / 2 > dp[n];
}
int main(){int t;cin>>t;while(t--){cin>>n>>k;for(int i=1;i<=n;i++)cin>>a[i];if(n<=k){sort(a+1,a+n+1);cout<<a[(n+1)/2]<<'\n';continue;}// check(7);int l=1,r=1000000001;while(l+1<r){int mid=(r+l)>>1;if(check(mid))l=mid;else r=mid;}cout<<l<<'\n';}return 0;
}

求>=x的数量

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 5e5 + 2;
int n,k;
ll dp[N],dp2[N];
int a[N];
int ans;
bool check(int x){for(int i=1;i<=k;i++){dp[i]=dp[i-1]+(a[i]>=x);dp2[i]=dp[i];}dp2[k]=0;for(int i=k+1;i<=n;i++){if(i%k==0){dp2[i]=dp2[i-k];continue;}dp2[i]=max(dp2[i-1]+(a[i]>=x),dp2[i-k]);}for(int i=k+1;i<=n;i++){dp[i]=max(dp2[i-1]+(a[i]>=x),dp[i-k]);}int tmp=n%k;if(tmp==0)tmp=k;return dp[n]>=((tmp)/2+1);
}
int main(){ios::sync_with_stdio(0);cin.tie(0);int t;cin>>t;while(t--){cin>>n>>k;for(int i=1;i<=n;i++)cin>>a[i];if(n<=k){sort(a+1,a+n+1);cout<<a[(n+1)/2]<<'\n';continue;}int l=1,r=INT_MAX;while(l+1<r){int mid=(r+l)>>1;if(check(mid))l=mid;else r=mid;}cout<<l<<'\n';}return 0;
}

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com