[Codeforces #295(Div 2)]简要题解

A. Pangram

A word or a sentence in some language is called a pangram if all the characters of the alphabet of this language appear in it at least once. Pangrams are often used to demonstrate fonts in printing or test the output devices.

You are given a string consisting of lowercase and uppercase Latin letters. Check whether this string is a pangram. We say that the string contains a letter of the Latin alphabet if this letter occurs in the string in uppercase or lowercase.

Input
The first line contains a single integer n (1 ≤ n ≤ 100) — the number of characters in the string.

The second line contains the string. The string consists only of uppercase and lowercase Latin letters.

Output
Output “YES”, if the string is a pangram and “NO” otherwise.
题目大意
给一个长度为n的字符串,问是否从a到z的所有字母都在这个字符串中出现过
题解
签到水题

#include 
#include 
using namespace std;

int n;
char s[120];
bool vis[200];

int main()
{
    scanf("%d",&n);
    scanf("%s",s+1);
    for(int i=1;i<=n;i++)
    {
        if(s[i]>='A'&&s[i]<='z') vis[s[i]-'A']=true;
        if(s[i]>='a'&&s[i]<='z') vis[s[i]-'a']=true;
    }
    for(int i=0;i<26;i++)
        if(!vis[i])
        {
            printf("NO\n");
            return 0;
        }
    printf("YES\n");
    return 0;
}

B. Two Buttons

Vasya has found a strange device. On the front panel of a device there are: a red button, a blue button and a display showing some positive integer. After clicking the red button, device multiplies the displayed number by two. After clicking the blue button, device subtracts one from the number on the display. If at some point the number stops being positive, the device breaks down. The display can show arbitrarily large numbers. Initially, the display shows number n.

Bob wants to get number m on the display. What minimum number of clicks he has to make in order to achieve this result?

Input
The first and the only line of the input contains two distinct integers n and m (1 ≤ n, m ≤ 104), separated by a space .

Output
Print a single number — the minimum number of times one needs to push the button required to get the number m out of number n.
题目大意
给出数字 n,m ,现在要对 n 做若干次操作,每次操作可以将 n 乘上2或者减去1,问最少操作多少次,让 nm
题解
广搜一遍即可, 为了加快速度,可以用一个堆来进行优化。当然也可以贪心。

#include 
#include 
#include 

using namespace std;

struct node
{
    int num,step;
};

bool operator<(node a,node b)
{
    if(a.step==b.step) return a.numstep>b.step;
}

bool operator>(node a,node b)
{
    if(a.step==b.step) return a.num>b.num;
    return a.stepstep;
}

priority_queueq;

bool vis[41000];

int main()
{
    int n,m;
    scanf("%d%d",&n,&m);
    node now;
    now.num=n,now.step=0;
    q.push(now);
    while(!q.empty())
    {
        now=q.top();
        q.pop();
        if(now.num==m)
        {
            printf("%d\n",now.step);
            return 0;
        }
        if(now.numnow.num*2])
        {
            node next=now;
            next.num*=2;
            next.step++;
            vis[now.num*2]=true;
            q.push(next);
        }
        if(now.num>1&&!vis[now.num-1])
        {
            node next=now;
            next.num--;
            next.step++;
            vis[now.num-1]=true;
            q.push(next);
        }
    }
    return 0;
}

C. DNA Alignment

Vasya became interested in bioinformatics. He’s going to write an article about similar cyclic DNA sequences, so he invented a new method for determining the similarity of cyclic sequences.

Let’s assume that strings s and t have the same length n, then the function h(s, t) is defined as the number of positions in which the respective symbols of s and t are the same. Function h(s, t) can be used to define the function of Vasya distance ρ(s, t):
这里写图片描述
where is obtained from string s, by applying left circular shift i times. For example,
ρ(“AGC”, “CGT”) = 
h(“AGC”, “CGT”) + h(“AGC”, “GTC”) + h(“AGC”, “TCG”) + 
h(“GCA”, “CGT”) + h(“GCA”, “GTC”) + h(“GCA”, “TCG”) + 
h(“CAG”, “CGT”) + h(“CAG”, “GTC”) + h(“CAG”, “TCG”) = 
1 + 1 + 0 + 0 + 1 + 1 + 1 + 0 + 1 = 6
Vasya found a string s of length n on the Internet. Now he wants to count how many strings t there are such that the Vasya distance from the string s attains maximum possible value. Formally speaking, t must satisfy the equation: 这里写图片描述.

Vasya could not try all possible strings to find an answer, so he needs your help. As the answer may be very large, count the number of such strings modulo 109+7 .

Input
The first line of the input contains a single integer n (1n105) .

The second line of the input contains a single string of length n, consisting of characters “ACGT”.

Output
Print a single number — the answer modulo 109+7 .

题目大意
对于字符串 st ,定义 ρ(s,t) 如下:
这里写图片描述
如:
ρ("AGC","CGT")=
h("AGC","CGT")+h("AGC","GTC")+h("AGC","TCG")+
h("GCA","CGT")+h("GCA","GTC")+h("GCA","TCG")+
h("CAG","CGT")+h("CAG","GTC")+h("CAG","TCG")=
1+1+0+0+1+1+1+0+1=6
给出长度为 ns ,求有多少个不同的字符串 t 满足这里写图片描述

题解
其实这个题非常的水。。。但是它的题面长,而且四个样例都很特殊,难以发现特点,坑得我一直没做出来。实际上可以发现,使得 ρ(s,t) 最大的 t 串,其中的所有字母一定都是出现次数最多的字母。那么我们就相当于构造一个长度为 n 的字符串,这个串中的每个字母都是原来 s 中出现次数最多的字母。由于 s 串中出现次数最多的字母可能不止一个,因此我们首先要找出 s 中有多少种出现次数最多的字母,设共 tot 种。因为这个字符串只能由A、T、C、G四种字母组成,因此最多有四种出现次数最多的字母。然后构造长度为 nt ,每个位置可以选填 tot 种字母中的一个,因此最终的答案是 totn mod (109+7)

#include 
#include 
#include 

#define MAXN 110000
#define MOD 1000000007

using namespace std;

typedef long long int LL;

int n;
char s[MAXN],tmp[MAXN];

LL mul(LL a,LL b)
{
    LL ans=0;
    while(b)
    {
        if(b&1) ans=(ans+a)%MOD;
        a=(a+a)%MOD;
        b>>=1;
    }
    return ans;
}

LL fastPow(LL base,int pow)
{
    LL ans=1;
    while(pow)
    {
        if(pow&1) ans=mul(ans,base);
        base=mul(base,base);
        pow>>=1;
    }
    if(ans<0) ans+=MOD;
    return ans;
}

int sum[MAXN];

int main()
{
    scanf("%d",&n);
    scanf("%s",s+1);
    int maxsum=-1,tot=0;
    for(int i=1;i<=n;i++)
    {
        if(s[i]=='A') sum[1]++;
        else if(s[i]=='G') sum[2]++;
        else if(s[i]=='C') sum[3]++;
        else sum[4]++;
    }
    for(int i=1;i<=4;i++)
        if(sum[i]>maxsum)
            maxsum=sum[i];
    for(int i=1;i<=4;i++)
        if(sum[i]==maxsum)
            tot++;
    printf("%I64d\n",fastPow((LL)tot,n));
    return 0;
}

D. Cubes

Once Vasya and Petya assembled a figure of m cubes, each of them is associated with a number between 0 and m - 1 (inclusive, each number appeared exactly once). Let’s consider a coordinate system such that the OX is the ground, and the OY is directed upwards. Each cube is associated with the coordinates of its lower left corner, these coordinates are integers for each cube.

The figure turned out to be stable. This means that for any cube that is not on the ground, there is at least one cube under it such that those two cubes touch by a side or a corner. More formally, this means that for the cube with coordinates (x, y) either y = 0, or there is a cube with coordinates (x - 1, y - 1), (x, y - 1) or (x + 1, y - 1).

Now the boys want to disassemble the figure and put all the cubes in a row. In one step the cube is removed from the figure and being put to the right of the blocks that have already been laid. The guys remove the cubes in such order that the figure remains stable. To make the process more interesting, the guys decided to play the following game. The guys take out the cubes from the figure in turns. It is easy to see that after the figure is disassembled, the integers written on the cubes form a number, written in the m-ary positional numerical system (possibly, with a leading zero). Vasya wants the resulting number to be maximum possible, and Petya, on the contrary, tries to make it as small as possible. Vasya starts the game.

Your task is to determine what number is formed after the figure is disassembled, if the boys play optimally. Determine the remainder of the answer modulo 109+9 .

Input
The first line contains number m(2m105) .

The following m lines contain the coordinates of the cubes xi,yi(109xi109,0yi109) in ascending order of numbers written on them. It is guaranteed that the original figure is stable.

No two cubes occupy the same place.

Output
In the only line print the answer to the problem.

题目大意
给出 n 个方块以及它们的坐标,第 i 个方块的标号是 i 。定义一个方块是稳定的,当且仅当它是在地面上( y 坐标为0)或者它与下面的一个方块八连通,现在两个人要在这个坐标系上做游戏,每次取一个方块,并保证取完以后剩下的方块仍然都是稳定的,取完 n 次后,将 n 次取的方块的标号依次排列起来形成一个 nn 进制数。先手想让这个数尽量大,后手想让这个数尽量小,双方均采用最优策略,问最后这个数字是多少
思路
比较显然,先手一定是尽量取大标号的方块,后手一定是尽量取小标号的方块,我们可以用一个set来维护一个优先队列(为什么不用Priority queue?因为它不能访问队尾的元素,很麻烦),set可以取队首的最小元素,也可以取队尾的最大元素,符合题目需求。那么我们就要时刻保证set中的所有方块,删去任意一个都不会破坏当前剩下的方块的稳定性。
然后就是模拟先手和后手轮流下游戏的过程了。每次删掉某个方块后,要更新可能受到它影响的方块是否还能在下一次操作中被删去。具体的范围是 (x2,y2)(x+2,y+2)
一个很明显的例子,比如说
.1.
2.3
假如现在删去3,那么就会导致下一步2不能删。
具体细节看代码吧,注释说明得很清楚

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

#define MAXN 110000
#define MOD 1000000009

using namespace std;

typedef unsigned long long int ULL;

int n;
ULL ans=0;

struct Point
{
    int x,y; //某个方块的坐标
    Point(){}
    Point(int _x,int _y):x(_x),y(_y){}
}points[MAXN];

bool operator<(Point a,Point b)
{
    if(a.x==b.x) return a.yreturn a.xbool operator>(Point a,Point b)
{
    if(a.x==b.x) return a.y>b.y;
    return a.x>b.x;
}

mapmp; //mp[i]=点i的标号,为0表示点i已经被用过了
setheap; //用set来模拟一个像堆一样的神奇数据结构

int check(int x,int y) //检查(x,y)的下面有多少个格子与它联通
{
    int ans=0;
    for(int i=-1;i<=1;i++)
        if(mp[Point(x+i,y-1)])
            ans++;
    return ans;
}

void update(int x,int y) //删去(x,y)后,检查受他影响的方块是否还是稳定的
{
    bool flag=true; //flag=true表示可以拆(x,y) (拆了(x,y)后受他影响的点仍然稳定)
    for(int i=-1;i<=1;i++)
        if(mp[Point(x+i,y+1)]&&check(x+i,y+1)==1) //拆了(x,y)后,他下面八连通的格子中有变成不稳定的格子
            flag=false;
    if(!flag) //不能删去(x,y),将它从heap中删去
    {
        if(heap.count(mp[Point(x,y)]))
                heap.erase(mp[Point(x,y)]);
    }
    else //可以删去(x,y),把它加入heap
        if(!heap.count(mp[Point(x,y)]))
            heap.insert(mp[Point(x,y)]);
}

int main()
{
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
    {
        scanf("%d%d",&points[i].x,&points[i].y);
        mp[points[i]]=i;
    }
    for(int i=1;i<=n;i++) //初始时把所有可以删的点都放入heap
        update(points[i].x,points[i].y);
    for(int i=1;i<=n;i++)
    {
        int p; //p=要删除的点的标号
        if(i&1) //先手,删标号最大的点
        {
            p=*heap.rbegin();
            heap.erase(p);
            ans=(ans*n+p-1)%MOD;
        }
        else //后手,删标号最小的点
        {
            p=*heap.begin();
            heap.erase(p);
            ans=(ans*n+p-1)%MOD;
        }
        mp[points[p]]=0; //标记点p已经用过
        for(int i=-2;i<=2;i++) //在x-2,y-2到x+2,y+2范围内检查这些点还能否删去
            for(int j=-2;j<=2;j++)
                if(mp[Point(points[p].x+i,points[p].y+j)])
                    update(points[p].x+i,points[p].y+j);
    }
    printf("%I64u\n",ans);
    return 0;
}

E. Pluses everywhere

Vasya is sitting on an extremely boring math class. To have fun, he took a piece of paper and wrote out n numbers on a single line. After that, Vasya began to write out different ways to put pluses (“+”) in the line between certain digits in the line so that the result was a correct arithmetic expression; formally, no two pluses in such a partition can stand together (between any two adjacent pluses there must be at least one digit), and no plus can stand at the beginning or the end of a line. For example, in the string 100500, ways 100500 (add no pluses), 1+00+500 or 10050+0 are correct, and ways 100++500, +1+0+0+5+0+0 or 100500+ are incorrect.

The lesson was long, and Vasya has written all the correct ways to place exactly k pluses in a string of digits. At this point, he got caught having fun by a teacher and he was given the task to calculate the sum of all the resulting arithmetic expressions by the end of the lesson (when calculating the value of an expression the leading zeros should be ignored). As the answer can be large, Vasya is allowed to get only its remainder modulo 109+7 . Help him!

Input
The first line contains two integers, n and k (0k<n105) .

The second line contains a string consisting of n digits.

Output
Print the answer to the problem modulo 109+7 .
题目大意
给出一个长度为 n 的数字序列,用 k 个加号将它分割成若干个数字,并得到这个算式的最终答案(数字和),求所有划分方案的答案之和。
1082 种划分方案: (10)+81+(08) ,所有方案的算式答案之和为 18+9=27
题解
为了方便叙述,以下说第 i 位就是说从低位到高位数的第 i
注意到对于第 1n 位,每一位数字在最终的划分方案中充当中间的一个划分块的个位的次数是相同的,充当中间的一个划分块的十位的次数也是相同的……由此我们可以枚举所有数字在最终答案中充当中间的一个划分块的第 i 位所提供的贡献。每个数字在最终答案中充当中间一个划分块的第 i 位的次数是 Ck1(k1)ni1(ni1)
所有数字在最终答案中充当xxxx的第 i 位参与的贡献是 sum[ni]×10i1×Ck1ni1,sum[i]1i 位数位(第i位到最高位数位)的前缀和(因为个位到第i-1位不能充当一个块中的第i位,所以不能算入贡献)。
然后还有特殊情况:对于最右边的划分块而言,它的右边是没有加号的,加号只能往左边放,里面的数字 x 充当这个划分块第 i 位的贡献是 x×10i1×Ckni

#include 
#include 
#include 
#include 
#include 

#define MAXN 110000
#define MOD 1000000007

using namespace std;

typedef long long int LL;

char s[MAXN];
LL sum[MAXN],pow[MAXN]; //pow[i]=10^i
LL fact[MAXN]; //fact[i]=i!
LL ans=0;

LL extGCD(LL a,LL b,LL &x,LL &y) //ax+by=gcd(a,b)
{
    if(!b)
    {
        x=1;
        y=0;
        return a;
    }
    LL gcd=extGCD(b,a%b,x,y);
    LL t=x;
    x=y;
    y=t-a/b*y;
    return gcd;
}

LL rev(LL a,LL mod) //求a在模mod意义下的乘法逆元
{
    LL x,y;
    extGCD(a,mod,x,y);
    return (x%mod+mod)%mod;
}

LL C(LL n,LL m) //n个里选m个
{
    if(n<m) return 0;
    return fact[n]*rev(fact[m],MOD)%MOD*rev(fact[n-m],MOD)%MOD;
}

int main()
{
    int n,k;
    scanf("%d%d",&n,&k);
    scanf("%s",s+1);
    for(int i=1;i<=n;i++)
        sum[i]=(sum[i-1]+s[i]-'0')%MOD;
    if(!k) //特判无加号的情况
    {
        for(int i=1;i<=n;i++)
            ans=(ans*10+s[i]-'0')%MOD;
        printf("%I64d\n",ans);
        return 0;
    }
    fact[0]=1;
    for(int i=1;i<=n;i++) fact[i]=(fact[i-1]*i)%MOD;
    pow[0]=1;
    for(int i=1;i<=n;i++) pow[i]=(pow[i-1]*10)%MOD;
    for(int i=1;i<=n;i++) //枚举所有数在第i位的总贡献
    {
        ans=(ans+(LL)(sum[n-i])*pow[i-1]%MOD*C(n-i-1,k-1))%MOD;
        ans=(ans+(LL)(s[n-i+1]-'0')*pow[i-1]%MOD*C(n-i,k))%MOD;
    }
    printf("%I64d\n",ans);
    return 0;
}

你可能感兴趣的:(比赛题解,CodeForces,比赛赛题)