每日一题~div4 964 E+F+G (思维?数数?交互?有手就行?)大失败的两个小时

E
题意:
对于区间[l r]之中的数。我们选出两个数字来,分别进行乘三的操作,和除三(向下取整),至少需要多少次操作,使得全部的数变成零。
在这里插入图片描述
我们可以将log 的数值,预处理出来。同时注意到t=1e4, r=2e5.
如果每次累加起来就会超时。所以我们处理log的前缀和。

#include <bits/stdc++.h>
using namespace std;
#define int long long 
const int N=2e5+10;
int log_3[N];
void init()
{
    log_3[1]=0;log_3[0]=0;
    log_3[3]=1;
    for (int i=3;i<=N;i++)
        log_3[i]=log_3[i/3]+1;
    //处理前缀和
    for (int i=1;i<=N;i++)
    {
        log_3[i]+=log_3[i-1];
    }
}
void solve()
{
    int l,r;cin>>l>>r;
    int ans=0;
    ans+=2*(log_3[l]-log_3[l-1]+1);   
    ans+=log_3[r]-log_3[l]+(r-l);
    
    cout<<ans<<"\n";
}

F
题意:
二进制的数组。取出数组长度为k(k为奇数)的所有子序列。求出他们的中位数(排序之后,在中间位置的数字,因为中位数还要排序,其实就没有了子序列中的相对顺序的限制,可以随便选了)的和,输出和mod1e9+7

中位数不是0就是1,所以一个子序列的贡献不是0,就是1.也就是说中位数是1的时候,才有贡献,否则没有影响。
因为只有01,所以只要这个子序列中的0的个数小于等于 k/2,中位数就是1.那么这几个子序列就会贡献1.
现在的问题就是 这样的子序列的有多少个。
可以统计数组中0 和1 的个数。
枚举0的个数,利用组合数求解。
在这里插入图片描述
多mod总是没错的^ _ ^

#include <bits/stdc++.h>
using namespace std;
#define int long long 
const int mod=1e9+7;
const int N=2e5+10;
int f[N],g[N];
int qpow(int a,int b)
{
    int ans=1;a%=mod;
    while(b){
        if (b&1)ans=ans*a%mod;
        a=a*a%mod;
        b>>=1;
    }
    return  ans;
}
void init()
{
    f[0]=g[0]=1;
    for (int i=1;i<N;i++)
    {
        f[i]=f[i-1]*i%mod;
        //逆元
        g[i]=g[i-1]*qpow(i,mod-2)%mod;
    }
}
int getc(int n,int m){
    if (m>n)return 0;
    return f[n]*g[m]%mod*g[n-m]%mod;
}
void solve()
{
   
    int n,k;cin>>n>>k;
    vector<int>a(n);int cnt[2]{};
    for (int i=0;i<n;i++)
        cin>>a[i],cnt[a[i]]++;
        
    int tar=k/2;int ans=0;
    for (int i=0;i<=tar;i++)
    {
        ans+=(getc(cnt[0],i)*getc(cnt[1],k-i)%mod)%mod;
    }
    cout<<ans%mod<<"\n";

}

G
题意:
交互题,有一个数x(2~999)
如果y<x 返回的是 y
否则是 y+1
3^7=2187 >999.所以可以在7次询问之前,找到答案。

#include <bits/stdc++.h>
using namespace std;
#define ll long long 
int ask(int x,int y)
{
    cout<<"? "<<x<<" "<<y<<endl;
    int ans;cin>>ans;
    return ans;
}
void solve()
{
  
    int l=2,r=999;
    while(l<=r)
    {
        int midl=l+(r-l)/3;
        int midr=r-(r-l)/3;
        int now=ask(midl,midr);
        if (now==midl*midr)
        {
            l=midr+1;
        }else if (now==midl*(midr+1))
            l=midl+1,r=midr-1;
        else r=midl-1;
    }
    
    cout<<"! "<<l<<endl;
}
int  main()
{
    std::cin.tie(nullptr)->sync_with_stdio(false);
    int t; cin>>t;
    while(t--)
    {
        solve();
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值