codeforces Round 964 div4 (A~G2)

做了一场cf 964 div4,本场链接放到这里了CFround964 div4   这场题质量真的很好

-好在也算ak了


A,B,C都没什么太多好说的,简单模拟即可,下面分享一下我的代码——


目录

A题

思路分析

代码实现

B题

思路分析

代码实现

扫描二维码关注公众号,回复: 17469641 查看本文章

C题

思路分析

代码实现

D题

思路分析

代码实现

E题

思路分析

代码实现

F题

思路分析

代码实现

G1题

思路分析

代码实现

G2题

思路分析

代码实现

A题

思路分析

简单两位数数位求和

代码实现

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#define int long long 
#define x first 
#define y second 
using namespace std;
void solve()
{
    int n;
    cin>>n;
    cout<<n%10+n/10<<endl;
}
signed main()
{
    ios::sync_with_stdio(0);
    cin.tie(0),cout.tie(0);
    int t ;
    cin >> t;
    while(t--) solve();
}

B题

思路分析

直接模拟 Suneet 赢下局数的可能,很暴力-----

代码实现

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#define int long long 
#define x first 
#define y second 
using namespace std;
void solve()
{
    int res = 0;
    int c,d,a,b;
    cin >> c >> d >> a >> b;
    if((d>a&&c>=b)||(d>=a&&c>b)) res++;
    if((d>b&&c>=a)||(d>=b&&c>a)) res++;
    if((c>a&&d>=b)||(c>=a&&d>b)) res++;
    if((c>b&&d>=a)||(c>=b&&d>a)) res++;
    cout<<res<<endl;
}
signed main()
{
    ios::sync_with_stdio(0);
    cin.tie(0),cout.tie(0);
    int t ;
    cin >> t;
    while(t--) solve();
}

C题

思路分析

题目看起来很吓人,但是还是直接模拟就行,不过得注意一些细节,不然容易WA---

代码实现

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#define int long long 
#define x first 
#define y second 
using namespace std;
const int N = 2e5 + 10;
typedef pair<int,int> PII;
PII a[N];
void solve()
{
     int flag = 0;
     int n,s,m;
     cin>>n>>s>>m;
     for(int i = 1; i <= n; i++)  cin>>a[i].x>>a[i].y;
     sort(a+1,a+n+1);
     if(a[1].x >= s || m - a[n].y >= s ) 
     {
        cout<<"YES"<<endl;
        return ;
     }
     for(int i = 1; i < n; i++)
    {
          if(a[i+1].x - a[i].y >= s) 
          {
            flag = 1;
            cout<<"YES"<<endl;
            break;
          }   
    }
    if(!flag) cout<<"NO"<<endl;
}
signed main()
{
    ios::sync_with_stdio(0);
    cin.tie(0),cout.tie(0);
    int t ;
    cin >> t;
    while(t--) solve();
}

D题

思路分析

算是思维题加上双指针,但其实不需要双指针一个指针也可以做,代码如下:

代码实现

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#define int long long 
#define x first 
#define y second 
using namespace std;
void solve()
{
     string s,t;
     cin>>s>>t;
     int i = 0;
     for(auto c:t)
     {
        while(i<s.size()&&s[i]!=c&&s[i]!='?')  
        {
            i++;
        }
        if(i==s.size()) 
        {
            cout<<"NO"<<endl;
            return ;
        }
        else  
        {
            s[i] = c;
            i++;
        }
     }
     cout<<"YES"<<endl;
     
     for(auto &c:s)
     {
        if(c=='?') c = 'a';
     }
     cout<<s<<endl;
}
signed main()
{
    ios::sync_with_stdio(0);
    cin.tie(0),cout.tie(0);
    int t ;
    cin >> t;
    while(t--) solve();
}

E题

思路分析

本题题意是在 l 到 r (包含l 和 r)这个区间内任意选两个数执行Op1和Op2,我们规定

  1. Op1:将x乘以3变为3x
  2. Op2:将y除以3向下取整变为[y / 3] 

 我们现在需要在l和r区间内任选两个数进行 两种不同的操作使整个序列的数都变为0,问最小操作次数。

  1. 因此我们可以想到贪心,当Op1只给0用,Op2给其他数用时会得到最小次数。所以我们应该先将最小的数l当成y一直进行Op2操作将其变为0,其他数当成x一直进行Op1操作。此时操作次数记为C[l]。
  2. 首先将第一步中进行Op1的数降回来,此时和第一步的次数一样为C[l],然后将l当成x执行Op1(反正一直为0),除l位置以外所有数当成y执行Op2,此时总次数为\sum_{i = l + 1}^{r} + C[l]
  3. 将两步的次数相加之后总次数是 \sum_{i = l + 1}^{r} C[i] + C[l] + C[l]  其实不难看出也就是\sum_{i = l }^{r} + C[l]

求和我们知道 l 和 r 在1到 2*10^{5} 的范围内,所以我们求和时要用到前缀和了,先把1到2e5+10之间的所有数除以3降到0所需要的步数存在step[N],先预处理前缀和,不然后面读入t 双重循环会TLE。

知道了这些 ,我们可以上代码了!—— 

代码实现

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#define int long long 
#define x first 
#define y second 
using namespace std;
const int N = 2e5 + 10;
const int N1 = 6e5 + 10;
int step[N];
int sum[N];
int get(int x)
{
    int cnt = 0;
    while(x)
    {
        cnt++;
        x/=3;
    }
    return cnt;
}
void solve()
{
    int l,r;  cin>>l>>r;
    int res = get(l);//左边界,推出来的公式
    cout << sum[r] - sum[l-1] + res <<endl;
}
signed main()
{
    ios::sync_with_stdio(0);
    cin.tie(0),cout.tie(0);
    //必须先预处理,不然超时
    int j = 0;
    for(int i = 1; i <= N; i++)
    {
        step[++j] = get(i);
    }//每个整数除以3降到0的步数
    for(int i= 1;i <= N;i++) sum[i]=step[i]+sum[i-1];//前缀和
    int t ;
    cin >> t;
    while(t--) solve();
}

F题

思路分析

本题其实说的是在一个长度为n只包含0,1的数组里选取k个数,

将取这个数组中长度为 k ( k为奇数)的所有子序列 ,并找出它们的中位数。

所有这些值的和是多少? 在0,1数组里取子序列算中位数,中位数无非只有0和1两种,求和时0对答案是没贡献的,所以我们只用算子序列中中位数为1的情况个数就行了。

首先我们知道在长度为k的序列中至少也要有ceil(k*1.0/2)个1才能保证中位数不为0,我们记为sum_1。

其次这样就不得不用到组合数模版了,我们在sum1(数组中1的个数)中取i个1,sum2(数组中2的个数)中取(k - i)个0,两个组合数相乘即为所有的情况种数,但是要注意范围问题,我们for循环从sum_1遍历,i必须小于等于sum1且小于k,还有一个就是(k-i)小于等于sum0才是合法范围

组合数模版在 求组合数C(a,b) 说太多了,下面上代码哈哈-------

代码实现

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#define int long long 
#define x first 
#define y second 
using namespace std;
const int mod = 1e9 + 7;
const int N = 2e5 + 10;
int fact[N],infact[N];
int qmi(int a,int k,int p)
{
    int res = 1 % p;
    while(k)
    {
        if(k & 1) res = (int)res * a % p;
        a = (int)a * a % p;
        k >>= 1;
    }
    return res;
}
void init()
{
    fact[0] = infact[0] = 1;
    for(int i = 1; i < N; i++)
    {
        fact[i] = (int)fact[i-1] * i % mod ;
        infact[i] = (int)infact[i-1] * qmi(i,mod - 2,mod) % mod;
    }
}
int C(int a,int b)//计算组合数
{
    return (int)fact[a] * infact[b] % mod * infact[a-b] % mod;
}
void solve()
{
    int n,k;
    cin>>n>>k;
    int sum1 = 0;
    int sum0 = 0;
    for(int i = 0; i < n; i++)
    {
        int x;
        cin>>x;
        if(x == 0) sum0++;  else sum1++;
    }
    int sum_1 = ceil(k*1.0/2);//至少要有[k/2]+1个1才能保证中位数不为0
    if(sum_1 > sum1) 
    {
        cout<<"0"<<endl;
        return;
    }
    int ans = 0;
    for(int i = sum_1; i <= sum1 && i <= k ; i++)
    {
        if(k-i <= sum0)
        ans = (ans + C(sum1,i) * C(sum0,k-i) % mod) % mod;
    }
    cout<<ans<<endl;
}
signed main()
{
    ios::sync_with_stdio(0);
    cin.tie(0),cout.tie(0);
    init();
    int t;
    cin >> t;
    while(t--) solve();
    return 0;
}

G1题

思路分析

交互题,G1可以查询10次,2的10次方为1024,正好大于1000没多少,x在2到999刻度出错,

那就直接二分,得注意交互题的格式

代码实现

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#define int long long 
#define x first 
#define y second 
using namespace std;
void solve() 
{
    int l = 1,r = 999,ans = -1;
    while(l<=r)
    {
        int mid = l + r >> 1;
        cout<< "?" << ' ' << mid << ' ' << mid << endl;
        cout<<endl;
        int s ; cin >> s;
        if(mid * mid != s) r = mid - 1;
        else l = mid + 1,ans = mid ; 
    } 
    cout<< "!" << " " << ans + 1 << endl;
    
}

signed main()
{
    ios::sync_with_stdio(0);
    cin.tie(0),cout.tie(0);
    int t ;
    cin >> t;
    while(t--) solve();
}

G2题

思路分析

交互题,G2只能查询7次,就不能二分了,那我们就三分区间,两个断点分别为m1,m2。

代码实现

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#define int long long 
#define x first 
#define y second 
using namespace std;
int query(int a,int b)
{
    cout<<"?"<<" "<<a<<" "<<b<<endl;
    int s1;
    cin >> s1;
    return s1;
}
void f(int a)
{
    cout<<"!"<<" "<<a<<endl;
}
void solve()
{
    //三分区间
     int l = 1,r = 1000;
     while(l + 2 < r)//注意边界
     {
          int m1 = l + (r - l) / 3;
          int m2 = l + (r - l) / 3 * 2;
          int s = query(m1,m2);
          if(s == m1 *m2) l = m2; //m2左边未出错
          else if(s == m1 * (m2 + 1)) //m1和m2中间出错
          {
              l = m1;
              r = m2;
          }
          else r = m1;//否则为m1左边出错
    }
    if(l+1==r) f(r);//如果此时r就在l右边1格,则直接输出
    else 
    {
        int s = query(l,l+1);//否则再查询一下
        if(s==l*(l+1)) f(l+2);
        else f(l+1);
    }
}
signed main()
{
    ios::sync_with_stdio(0);
    cin.tie(0),cout.tie(0);
    int t ;
    cin >> t;
    while(t--) solve();
}

好了,本篇cf题解分享到此结束,欢迎大家讨论交流!!之后我还会不定期分享,感谢大家观看,希望大家能点赞收藏加关注哦~~~~~

猜你喜欢

转载自blog.csdn.net/weixin_73332175/article/details/141034613