ICPC-思维-CF#525div2 A+B+C+D

https://codeforces.com/contest/1088
A
给你数值x,x*x>x , x/x==1<x(x>=2)

ll n,m,t;
    cin>>n;
    if(n<2)cout<<-1<<endl;
    else cout<<n<<" "<<n<<endl;

B
给你长度为n的序列a,要求每次从中间抽出最小的正整数,同时让剩余的数都减这个正整数,输出m个正整数数列。

就是排序,记录减数前缀和,每次用这个前缀和比较原序列,大于0就输出并重新更新前缀和(在这里就是每一次的新的原序列值)

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define mem(a,b) memset(a,b,sizeof(a))
const double eps=1e-9;
const int inf=1e9;
const int maxn=1e5;
bool vis[maxn+5];
ll a[maxn+5];
int main(){
    ll n,m,t;
    cin>>n>>m;
    int sum=0;
    for(int i=0;i<n;i++){
        cin>>a[i];
    }
    sort(a,a+n);
    int k=0,temp;
    for(int j=0;j<m;j++){
        bool f=true;
        temp=k;
        for(int i=k;i<n;i++){
            if(a[i]-sum==0){
                temp++;
                continue;
            }
            if(a[i]-sum>0){
                cout<<a[i]-sum<<endl;
                f=false;
                sum=a[i];
                break;
            }
        }
        if(f)cout<<0<<endl;
        k=temp;
        //cout<<sum<<endl;
    }
    return 0;
}

C
我有长度为n的序列a, 我现在可以操作至多n+1步
OP1:对某前缀序列,所有元素都实现+x
OP2:对某前缀序列,所有元素都实现%x
要求一种方案,使得最后的序列是严格递增的(0,1,2,3,5…)

这题就是直接断定模数为n,因为n+1的操作就是都n个数都OP1,最后OP2得到的解。
每一位的最终态就是位置序。
从最后面开始计算次数和。

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define mem(a,b) memset(a,b,sizeof(a))
const double eps=1e-9;
const int inf=1e9;
const int maxn=1e5;
bool vis[maxn+5];
ll a[maxn+5];
ll b[maxn+5];
int main(){
    ll n,m,t;
    cin>>n;
    for(int i=0;i<n;i++){
        cin>>a[i];
        a[i]=a[i]%n;
    }
    int sum=0;
    b[n]=0;
    if(n-1-a[n-1]>=0){
        b[n-1]=n-1-a[n-1];
    }
    else  b[n-1]=(n-1-a[n-1]+n);
    a[n-1]=n-1;
    sum=b[n-1];
    int cnt=b[n-1]>0?1:0;
    for(int j=n-2;j>=0;j--){
        a[j]=(sum+a[j])%n;
        if(j-a[j]>=0)b[j]=j-a[j];
        else b[j]=j-a[j]+n;
        sum+=b[j];
        if(b[j]>0)cnt++;
    }
    cout<<cnt+1<<endl;
    for(int i=0;i<n;i++){
        if(b[i]==0)continue;
        cout<<"1 "<<i+1<<" "<<b[i]<<endl;
    }
    cout<<"2 "<<n<<" "<<n<<endl;
    return 0;
}

D
交互图,第一次写,懵
机器幕后设定,“a” “b”,你去输入“? c d ” 机器会回复你一些答案;
1 a ^ c > b ^ d
-1.a ^ c < b ^ d
0.a ^ c = b ^ d
要求你给入c d,评测机给你返回结果,你去判断最后的a,b值。

算是找规律吧!
就在逐位判断,tempa=a+1<<i 与b比较大小|||||a与tempb=b+(1<<i)比较大小
两个大小相同,那肯定是这一位的数值不同,所以大的那一位挑1
两个大小不同,且tempa ^ a < b ^ b说明这一位a,b都是1

例如题解中给的例子
Let's simulate for a = 6 and b = 5.
In the first query, we'll send (0, 0) to know that a > b.

In the second query, we'll send (4, 0) (the answer is -1) and (0, 4) (the answer is 1). 
Since the answers differ, this bit has the same value for a and b. 
Since the answer to the second query is 1, they both have a 1. 
Now, curA = curB = 4.

In the third query, we'll send (6, 4) (the answer is -1) and (4, 6) (the answer is -1).
 Since the answers are the same, a and b differ in this bit. 
 Since a is currently the greater, a has a 1 and b has a 0. 
 Now, the greater is b (the next time 2 bits differ, b will have a 1). 
 Also, curA = 6 and curB = 4.
 
In the last query, we'll send (7, 4) (the answer is 0) and (6, 5) (the answer is 0). 
Since the answers are the same, a and b differ in this bit. 
Since b is currently greater, b has a 1. 
Now, curA = 6 and curB = 5 and we're done :D

代码如下:

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define mem(a,b) memset(a,b,sizeof(a))
const double eps=1e-9;
const int inf=1e9;
const int maxn=1e5;
bool vis[maxn+5];
ll a[maxn+5];
ll b[maxn+5];
int ask(int a,int b){
    int res;
    printf("? %d %d\n",a,b);
    fflush(stdout);
    scanf("%d",&res);
    return res;
}
int main(){
    ll n,m,t;
    int jud=0;
    ll  a=0,b=0,tempa,tempb;
    int f=ask(0,0);//判断a,b大小
    ///为了避免前面的1对后面造成影响,必须连续两位判断
    for(ll i=29;i>=0;i--){
        tempa=a+(1<<i);//a1000
        tempb=b+(1<<i);//b1000
        //f是大小结果 temp1是比较(a1000 b0000)的结果 temp2是比较(a0000 b1000)的结果
        int temp1=ask(tempa,b);
        int temp2=ask(a,tempb);
        if(temp1==-1&&temp2==1){///这一位相同且a,b都是1
            a=tempa;
            b=tempb;
        }///若temp1==1&&temp2==-1,那么这一位相同且a,b都是0
        else if(temp1==temp2){///这一位不同(1/0)
            if(f>0)a=tempa;///a>=b
            else b=tempb;
            //判断目前a,b大小 不能用ask
            f=temp1;//发现temp1就是舍去当前位后,能判断a,b后面数值的大小
        }
    }
    printf("! %lld %lld\n",a,b);
    fflush(stdout);
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值