codeforces Round 964 div4 (A~G2)

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

-好在也算ak了


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


目录

A题

思路分析

代码实现

B题

思路分析

代码实现

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题解分享到此结束,欢迎大家讨论交流!!之后我还会不定期分享,感谢大家观看,希望大家能点赞收藏加关注哦~~~~~

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值