Codeforces Round #803 (Div. 2) D和E

题意:给定一个奇数长度的递增序列(1~n),里面只有一个数字没交换过位置,其余数字都分别交换过一次位置而且交换元素不相交。问在这个序列里哪个元素没有交换过。交互题,给定15次询问。每次返回你询问的区间的数字。

题解:利用二分来缩小询问区间,考虑区间内的数字是原来区间的数字的个数,如果和原来区间的数字交换,则个数增加2,和区间外换的话就没有个数增加。这样一来,如果答案那么没有移动过的数字在这个区间内,那么个数就是奇数个,否则在另外一半区间内。

#include<bits/stdc++.h>
using namespace std;
int n,k;
int a[1000010];
void q(int l,int r)
{
    cout<<"?"<<' '<<l<<' '<<r<<endl;
}
void solve()
{
    cin>>n;
    int l=1,r=n;
    while(l<r){
        int mid=l+r>>1;
        q(l,mid);
        int cnt=0;
        for(int i=1;i<=mid-l+1;i++)
        {
            int x;
            cin>>x;
            if(x>=l&&x<=mid) cnt++;
        }
        if(cnt%2==0) l=mid+1;
        else r=mid;
    }
    cout<<"!"<<' '<<l<<endl;

}

int main()
{
    int t=1;
    cin>>t;
    while(t--) solve();
    return 0;
}

E. PermutationForces II

题意:给定一个n和一个s,a数字的1~n的排列,b也是1~n的排列,但是隐藏的某些不重要的数字写成-1。接下来有n次操作,每次能移动i~i+n范围内的两个可重复的数字交换位置,问a有多少中交换方法使得a和b的排列一样。(bi为-1表示ai能是任意数字)

题解:

①.先求出有解的条件,如果ai-bi>s,那么就无解。假设有解,那么必定是要先把ai换小然后再换成bi,那么如果让ai换下来的话也不用费这事了,因为左边界是越来越大的,能够得着ai早就够到了,不用先用后面的去换。

②换完之后,要考虑怎么交换的问题,因为左边界越来越大,所以在第一次就要安排好1,第二次就要安排好2,慢慢递增,所以每次安排哪个数都是决定好了的。第一交换1的时候,如果b需要1,那么就把1回到原来的位置,否则就为1+s的范围内找-1的b对应的a去交换 ,不能和不是-1的b对应的a交换,否则会出现没有办法把1再换下来的情况。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=2e5+10;
int n;
int a[N],b[N],s;
int mod= 998244353;
void solve()
{
    cin>>n>>s;
    for(int i=1;i<=n;i++) cin>>a[i];
    for(int i=1;i<=n;i++) cin>>b[i];
    for(int i=1;i<=n;i++)
    {
        if(a[i]-b[i]>s&&b[i]!=-1){
            puts("0");
            return;
        }
    }

    vector<int> num(n+10,0),f(n+10,0);
    set<int> S;

    for(int i=1;i<=n;i++){
        if(b[i]==-1) num[a[i]]=1;
    }
    for(int i=1;i<=n;i++) num[i]+=num[i-1];
    ll ans=1;
    ll cnt=0;
    for(int i=1;i<=n;i++){
        if(b[i]!=-1) f[b[i]]=1;
    }
    for(int i=1;i<=n;i++)
    {
        if(!f[i]){
            ans=ans*(num[min(i+s,n)]-cnt);
            ans%=mod;
            cnt++;
        }
    }
    cout<<ans<<endl;
}

int main()
{
    int t=1;
    cin>>t;
    while(t--) solve();
    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值