zoukankan      html  css  js  c++  java
  • Codeforces 483

    题目链接:http://codeforces.com/contest/483


    A - Counterexample - [简单构造题]

    Your friend has recently learned about coprime numbers. A pair of numbers $(a, b)$ is called coprime if the maximum number that divides both $a$ and $b$ is equal to one.

    Your friend often comes up with different statements. He has recently supposed that if the pair $(a, b)$ is coprime and the pair $(b, c)$ is coprime, then the pair $(a, c)$ is coprime.

    You want to find a counterexample for your friend's statement. Therefore, your task is to find three distinct numbers $(a, b, c)$, for which the statement is false, and the numbers meet the condition $l le a < b < c le r$.

    More specifically, you need to find three numbers $(a, b, c)$, such that $l le a < b < c le r$, pairs $(a, b)$ and $(b, c)$ are coprime, and pair $(a, c)$ is not coprime.

    Input
    The single line contains two positive space-separated integers $l, r (1 le l le r le 10^18; r - l le 50)$.

    Output
    Print three positive space-separated integers $a, b, c$ — three distinct numbers $(a, b, c)$ that form the counterexample. If there are several solutions, you are allowed to print any of them. The numbers must be printed in ascending order.

    If the counterexample does not exist, print the single number $-1$.

    Examples
    Input
    2 4
    Output
    2 3 4
    Input
    10 11
    Output
    -1
    Input
    900000000000000009 900000000000000029
    Output
    900000000000000009 900000000000000010 900000000000000021
    Note
    In the first sample pair (2, 4) is not coprime and pairs (2, 3) and (3, 4) are.

    In the second sample you cannot form a group of three distinct integers, so the answer is -1.

    In the third sample it is easy to see that numbers 900000000000000009 and 900000000000000021 are divisible by three.

    题意:

    在给定的 $[l,r]$ 里找到三个数字 $a,b,c$,满足 $gcd(a,b) = 1, gcd(b,c) = 1, gcd(a,c) > 1$。

    题解:

    相邻两个整数必然互质,相邻两个奇数必然互质。因此只能找连续的三个为偶奇偶的数。

    AC代码:

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    ll l,r;
    int main()
    {
        cin>>l>>r;
        ll a=(l%2==0)?l:l+1;
        ll b=a+1, c=b+1;
        if(c<=r) printf("%lld %lld %lld
    ",a,b,c);
        else printf("-1
    ");
    }

    B - Friends and Presents - [二分]

    You have two friends. You want to present each of them several positive integers. You want to present $cnt_1$ numbers to the first friend and $cnt_2$ numbers to the second friend. Moreover, you want all presented numbers to be distinct, that also means that no number should be presented to both friends.

    In addition, the first friend does not like the numbers that are divisible without remainder by prime number $x$. The second one does not like the numbers that are divisible without remainder by prime number $y$. Of course, you're not going to present your friends numbers they don't like.

    Your task is to find such minimum number $v$, that you can form presents using numbers from a set $1, 2, ..., v$. Of course you may choose not to present some numbers at all.

    A positive integer number greater than $1$ is called prime if it has no positive divisors other than $1$ and itself.

    Input
    The only line contains four positive integers $cnt_1, cnt_2, x, y (1 le cnt1, cnt2 < 10^9; cnt1 + cnt2 le 10^9; 2 le x < y le 3·10^4)$ — the numbers that are described in the statement. It is guaranteed that numbers $x, y$ are prime.

    Output
    Print a single integer — the answer to the problem.

    Examples
    input
    3 1 2 3
    output
    5
    input
    1 3 2 3
    output
    4

    Note
    In the first sample you give the set of numbers {1, 3, 5} to the first friend and the set of numbers {2} to the second friend. Note that if you give set {1, 3, 5} to the first friend, then we cannot give any of the numbers 1, 3, 5 to the second friend.

    In the second sample you give the set of numbers {3} to the first friend, and the set of numbers {1, 2, 4} to the second friend. Thus, the answer to the problem is 4.

    题意:

    现在要给两个人赠送一些正整数,要给第一个人送 $cnt_1$ 个正整数,要给第二个人送 $cnt_2$ 个正整数,且第一个人不想要能被 $x$ 整除的数,第二个人不想要能被 $y$ 整除的数。

    现在你要求出最小的正整数 $v$,意味着你送出的正整数全部属于 $1 sim v$。

    题解:

    二分倒是不难想到,就是算怎么给两人整数不太好想。

    举个栗子:假设我现在 $v=7,x=2,y=3,cnt_1=3,cnt_2=3$,显然此时能给第一个人的数字有 $1,3,5,7$,能给第二个人的数字有 $1,2,4,5,7$;

    那么我们知道,为了尽量使得 $v$ 小,我们应该尽量把第二个人不要的数字塞给第一个人,比如第二个人是不要 $3$ 的,但第一个人要,所以可以塞给他;同理,第一个人不要 $2,4$,但是第二个人要,可以塞给他;

    假设 $1 sim v$ 中能被 $x$ 整除的数有 $cnt_x$ 个,能被 $y$ 整除的数有 $cnt_y$ 个,能被 $xy$ 整除的数有 $cnt_xy$ 个;因此,第二个人不要而第一个人要的数字,其数量为 $cnt_y - cnt_xy$,第一个人不要而第二个人要的数字,其数量为 $cnt_x - cnt_xy$;

    那么剩下来再要送出去的数字,就既不能被 $x$ 整除,也不能被 $y$ 整除了,如果这些数够分,那么 $v$ 就是可行的,不够分的话 $v$ 就不可行。

    AC代码:

    #include<bits/stdc++.h>
    using namespace std;
    int cnt1,cnt2,x,y;
    
    int judge(int v)
    {
        int cnt_x=v/x, cnt_y=v/y, cnt_xy=v/(x*y);
        int rest1=max(cnt1-(cnt_y-cnt_xy),0);
        int rest2=max(cnt2-(cnt_x-cnt_xy),0);
        return rest1+rest2<=v-cnt_x-cnt_y+cnt_xy;
    }
    
    int main()
    {
        ios::sync_with_stdio(0);
        cin.tie(0);
    
        cin>>cnt1>>cnt2>>x>>y;
        int l=1, r=2*(cnt1+cnt2);
        while(l<r)
        {
            int mid=l+(r-l)/2;
            if(judge(mid)) r=mid;
            else l=mid+1;
        }
        cout<<l<<'
    ';
    }

    C - Diverse Permutation - [构造题]

    Permutation $p$ is an ordered set of integers $p_1, p_2, cdots, p_n$, consisting of $n$ distinct positive integers not larger than $n$. We'll denote as n the length of permutation $p_1, p_2, cdots, p_n$.

    Your task is to find such permutation $p$ of length $n$, that the group of numbers $|p_1 - p_2|, |p_2 - p_3|, cdots, |p_{n-1} - p_n|$ has exactly $k$ distinct elements.

    Input
    The single line of the input contains two space-separated positive integers $n, k (1 le k < n le 10^5)$.

    Output
    Print $n$ integers forming the permutation. If there are multiple answers, print any of them.

    Examples
    Input
    3 2
    Output
    1 3 2
    Input
    3 1
    Output
    1 2 3
    Input
    5 2
    Output
    1 3 2 4 5

    题意:

    让你给出一个 $1 sim n$ 的某个排列 $p$,使得 $|p_1 - p_2|, |p_2 - p_3|, cdots, |p_{n-1} - p_n|$ 中包含 $k(1 le k le n-1)$ 个不同的数字。

    题解:

    实际上,要 $1 sim n$ 的排列 $p$ 最多可以让 $k=n-1$,换句话说,只需要 $1 sim k+1$ 的排列就能满足条件。

    然后,第一步,把 $1$ 放到 $k$ 和 $k+1$ 之间,即可产生 $k-1,k$ 这两个不同的数字,而后,把 $2$ 放到 $k-1$ 和 $k$ 之间可产生 $k-3,k-2$ 这两个不同的数字。依次类推即可。

    AC代码:

    #include<bits/stdc++.h>
    using namespace std;
    const int maxn=1e5+10;
    int n,k;
    int num[maxn];
    void fill(int v,int k)
    {
        if(k<=0) return;
        num[k]=v;
        num[k-1]=num[k+1]-1;
        fill(v+1,k-2);
    }
    int main()
    {
        cin>>n>>k;
        for(int i=k+1;i<=n;i++) num[i]=i;
        fill(1,k);
        for(int i=1;i<=n;i++) printf("%d%c",num[i],i<n?' ':'
    ');
    }

    D - Interesting Array - [线段树]

    We'll call an array of $n$ non-negative integers $a[1], a[2], ..., a[n]$ interesting, if it meets $m$ constraints. The $i$-th of the $m$ constraints consists of three integers $l_i, r_i, q_i (1 le l_i le r_i le n)$ meaning that value $a[l_i] & a[l_{i+1}] & cdots & a[r_i]$ should be equal to $q_i$.

    Your task is to find any interesting array of $n$ elements or state that such array doesn't exist.

    Expression $x$&$y$ means the bitwise AND of numbers $x$ and $y$. In programming languages C++, Java and Python this operation is represented as "&", in Pascal — as "and".

    Input
    The first line contains two integers $n, m (1 le n le 10^5, 1 le m le 10^5)$ — the number of elements in the array and the number of limits.

    Each of the next m lines contains three integers $l_i, r_i, q_i (1 le l_i le r_i le n, 0 le qi < 2^{30})$ describing the $i$-th limit.

    Output
    If the interesting array exists, in the first line print "YES" (without the quotes) and in the second line print n integers $a[1], a[2], ..., a[n] (0 le a[i] < 2^{30})$ decribing the interesting array. If there are multiple answers, print any of them.

    If the interesting array doesn't exist, print "NO" (without the quotes) in the single line.

    Examples
    Input
    3 1
    1 3 3
    Output
    YES
    3 3 3
    Input
    3 2
    1 3 3
    1 3 2
    Output
    NO

    题意:

    给出 $n,m$,若数组 $a[1 sim n]$ 满足 $m$ 项条件中的任意一项,则称它为有趣的。

    第 $i$ 项条件表述为 $l_i, r_i, q_i (1 le l_i le r_i le n, 0 le q_i < 2^{30})$,即要求 $a[l_i] & a[l_{i+1}] & cdots & a[r_i] = q_i$。

    现在要你构造一个有趣的数组 $a[1 sim n]$。

    题解:

    初始全部 $a[i]=0$;考虑每一组 $l_i, r_i, q_i$,既然要 $a[l_i] & a[l_{i+1}] & cdots & a[r_i] = q_i$,那么就应当对区间 $[l,r]$ 内所有的 $a[i]|=q[i]$。

    最后 $m$ 组要求全部完成后,再重新跑一遍 $m$ 个 $l_i, r_i, q_i$ 进行验证即可。

    AC代码:

    #include<bits/stdc++.h>
    using namespace std;
    const int maxn=1e5+10;
    const int maxm=1e5+10;
    int n,m;
    int l[maxm],r[maxm],q[maxm];
    
    /********************************* Segment Tree - st *********************************/
    struct Node{
        int l,r;
        int val,lazy;
        void update(int x)
        {
            val|=x;
            lazy|=x;
        }
    }node[4*maxn];
    void pushdown(int root)
    {
        if(node[root].lazy)
        {
            node[root*2].update(node[root].lazy);
            node[root*2+1].update(node[root].lazy);
            node[root].lazy=0;
        }
    }
    void pushup(int root)
    {
        node[root].val=node[root*2].val&node[root*2+1].val;
    }
    void build(int root,int l,int r) //对区间[l,r]建树
    {
        node[root].l=l; node[root].r=r;
        node[root].val=0; node[root].lazy=0;
        if(l==r) node[root].val=0;
        else
        {
            int mid=l+(r-l)/2;
            build(root*2,l,mid);
            build(root*2+1,mid+1,r);
            pushup(root);
        }
    }
    void update(int root,int st,int ed,int val)
    {
        if(st>node[root].r || ed<node[root].l) return;
        if(st<=node[root].l && node[root].r<=ed) node[root].update(val);
        else
        {
            pushdown(root);
            update(root*2,st,ed,val);
            update(root*2+1,st,ed,val);
            pushup(root);
        }
    }
    int query(int root,int st,int ed)
    {
        if(st>node[root].r || ed<node[root].l) return (1<<30)-1;
        if(st<=node[root].l && node[root].r<=ed) return node[root].val;
        else
        {
            pushdown(root);
            int ls=query(root*2,st,ed);
            int rs=query(root*2+1,st,ed);
            pushup(root);
            return ls&rs;
        }
    }
    /********************************* Segment Tree - ed *********************************/
    
    int main()
    {
        scanf("%d%d",&n,&m);
        build(1,1,n);
        for(int i=1;i<=m;i++)
        {
            scanf("%d%d%d",&l[i],&r[i],&q[i]);
            update(1,l[i],r[i],q[i]);
        }
    
        bool ok=1;
        for(int i=1;i<=m;i++)
        {
            if(query(1,l[i],r[i])!=q[i]) {
                ok=0; break;
            }
        }
        printf("%s
    ",ok?"YES":"NO");
        if(ok) for(int i=1;i<=n;i++) printf("%d%c",query(1,i,i),i<n?' ':'
    ');
    }

    E - Game with Strings - [期望+状压DP]

    You play the game with your friend. The description of this game is listed below.

    Your friend creates $n$ distinct strings of the same length $m$ and tells you all the strings. Then he randomly chooses one of them. He chooses strings equiprobably, i.e. the probability of choosing each of the $n$ strings equals $frac{1}{n}$. You want to guess which string was chosen by your friend.

    In order to guess what string your friend has chosen, you are allowed to ask him questions. Each question has the following form: «What character stands on position $pos$ in the string you have chosen?» A string is considered guessed when the answers to the given questions uniquely identify the string. After the string is guessed, you stop asking questions.

    You do not have a particular strategy, so as each question you equiprobably ask about a position that hasn't been yet mentioned. Your task is to determine the expected number of questions needed to guess the string chosen by your friend.

    Input
    The first line contains a single integer $n (1 le n le 50)$ — the number of strings your friend came up with.

    The next $n$ lines contain the strings that your friend has created. It is guaranteed that all the strings are distinct and only consist of large and small English letters. Besides, the lengths of all strings are the same and are between $1$ to $20$ inclusive.

    Output
    Print the single number — the expected value. Your answer will be considered correct if its absolute or relative error doesn't exceed $10^{-9}$.

    Examples
    Input
    2
    aab
    aac
    Output
    2.000000000000000
    Input
    3
    aaA
    aBa
    Caa
    Output
    1.666666666666667
    Input
    3
    aca
    vac
    wqq
    Output
    1.000000000000000

    题意:

    给出 $n$ 个等长 $m$ 的字符串,对方会等可能地选择其中一个字符串,我不知道他选择了哪个,所以每次会等可能地询问对方某个位置上是什么字符。

    一旦能够唯一确定是哪个字符串,我就停止询问。求我询问次数的期望。

    题解:

    假设 $dp[sta]$ 表示进行 $sta$ 状态询问的概率,这样一来,要完成状态转移,必须要知道在进行该状态的询问后是否已经确定对方选定的串。

    如果已经确定对方选定的串,那么我们就不需要再询问了;否则还要再询问一个位置,那么这个多一次的询问,对于整个询问数目的期望的贡献就为 $dp[sta] imes 1$。

    我们可以使用 $f[same]$ 来表示 $same$ 状态的位置上字符全部相同的字符串有哪些。然后我们发现,$f[same]$ 也是可以用dp求出来的,一开始我们 $O(n^2)$ 地求出初始条件:对于任意两个字符串 $i,j(i<j)$,他们所有的同位置上相同的字符可表示成状态 $same$($1$ 表示相同,$0$ 表示不同),即有初始条件 $f[same]=(1<<i)|(1<<j)$。其后我们可以dp求出全部的 $f[same]$,如果 $same_1$ 状态包含$same_2$ 状态,那么 $same_1$ 状态下不能区分的字符串在 $same_2$ 状态下一样无法区分。

    接下来考虑如何根据 $dp[sta]$ 求期望,$f[sta]$ 里有 $k$ 个 $1$ 代表有 $k$ 个串尚不能分辨,那么对于询问这 $k$ 个串其中一个,询问期望就是 $dp[sta]×1$,其他0的位置就是已经不需要询问了,1的位置这次询问是这次必须的,之后还询问不询问不知道,还询问不询问是后面的状态所决定的,对于 $k$ 个询问次数期望就是 $dp[sta] imes k$,对于最后的答案自然是加 $dp[sta] imes k / n$。其实主要思想就是利用期望的可加性,分开来算。

    AC代码:

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    const int maxn=53;
    const int maxm=23;
    
    int n,m;
    char s[maxn][maxm];
    double dp[1<<20];
    ll f[1<<20];
    inline int cntbit(int x){return x?(x&1)+cntbit(x>>1):0;}
    int main()
    {
    
        scanf("%d",&n);
        for(int i=0;i<n;i++) scanf("%s",s[i]);
        m=strlen(s[1]);
    
        //f[same]初始化
        memset(f,0,sizeof(f));
        for(int i=0;i<n;i++)
        {
            for(int j=i+1;j<n;j++)
            {
                int same=0;
                for(int k=0;k<m;k++) {
                    if(s[i][k]==s[j][k]) same|=(1<<k);
                }
                f[same]|=(1LL<<j)|(1LL<<i);
            }
        }
    
        //dp求所有的f[same]
        for(int same=(1<<m)-1;same>=0;same--)
        {
            for(int i=0;i<m;i++) {
                if(same&(1<<i)) f[same^(1<<i)]|=f[same];
            }
        }
    
        double ans=0;
        memset(dp,0,sizeof(dp)); dp[0]=1;
        for(int sta=0;sta<(1<<m);sta++)
        {
            if(f[sta]==0) continue;
    
            int cnt=cntbit(sta);
            for(int i=0;i<m;i++)
            {
                if(sta&(1<<i)) continue;
                dp[sta|(1<<i)]+=dp[sta]/(m-cnt);
            }
    
            for(int i=0;i<n;i++) {
                if(f[sta]&(1LL<<i)) ans+=dp[sta];
            }
        }
    
        printf("%.10f
    ",ans/n);
    }

    说实话,这题为什么这么求期望我还是云里雾里的……应该是我飘了,期望和概率题也敢碰了……

  • 相关阅读:
    布局的诡异bug合集+解决方法(更新中)
    java并发:CopyOnWriteArrayList简单理解
    java集合: LinkedList源码浅析
    Idea设置类注释模板
    jquery使用FormData提交数据
    postman发送json请求
    消息队列的简单理解
    如何设计一个消息队列?
    SpringBoot配置logback
    linux下安装kafka
  • 原文地址:https://www.cnblogs.com/dilthey/p/9951690.html
Copyright © 2011-2022 走看看