Codeforces 483 - A/B/C/D/E - (Done)

题目连接:http://codeforces.com/contest/483
node


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.ios

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.c++

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.dom

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

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.ui

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

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.spa

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

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\n",a,b,c);
    else printf("-1\n");
}

 


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<<'\n';
}

 


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?' ':'\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\n",ok?"YES":"NO");
    if(ok) for(int i=1;i<=n;i++) printf("%d%c",query(1,i,i),i<n?' ':'\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] \times 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] \times k$,对于最后的答案天然是加 $dp[sta] \times 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\n",ans/n);
}

说实话,这题为何这么求指望我仍是云里雾里的……应该是我飘了,指望和几率题也敢碰了……

相关文章
相关标签/搜索