码迷,mamicode.com
首页 > 其他好文 > 详细

【bestcoder #36】ABCD题解

时间:2015-04-06 08:51:50      阅读:179      评论:0      收藏:0      [点我收藏+]

标签:bestcoder   思路题   容斥原理   排列组合   

Strange Class

Accepts: 519 Submissions: 1749
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others)
问题描述
在Vivid的学校里,有一个奇怪的班级(SC).在SC里,这些学生的名字非常奇怪。他们的名字形式是这样的anbncn(a,b,c两两不相同。).例如,叫”abc”,”ddppqq”的学生是在SC里的,然而叫”aaa”,”ab”,”ddppqqq”的同学并不是在SC里的。
Vivid交了许多的朋友,他想知道他们之中哪些人是在SC里的。
输入描述
多组测试数据(大概10组),每一个数据在一行中给出一个字符串S,代表Vivid一个朋友的名字。
请处理到文件末尾。

[参数约定]
1≤|S|≤10.
|S| 是指S的长度.
S 只包含小写字母.
输出描述
对于每一个数据,如果Vivid的朋友是SC里的,那么输出YES,否则输出NO。
输入样例
abc
bc
输出样例
YES
NO

WA两次才过,第一次没看到abc必须是连续的;第二次没看到abc必须两两不同。

#include <iostream>
#include <cstring>
#include <cmath>
#include <cstdio>
#include <cstdlib>
#include <algorithm>
using namespace std;
char s[100];
int cnt[100];
int main()
{
    while (scanf("%s",s)!=EOF)
    {
        for (int i=1;i<=30;i++)
            cnt[i]=0;
        int l=strlen(s);
        int num=0;
        if (l<3)
        {
            cout<<"NO"<<endl;
            continue;
        }
        int k;
        int now=0,f=1;
        while (now<l)
        {
            int x=now;
            while (now+1<l&&s[now]==s[now+1])
                now++;
            num++;
            if (cnt[s[now]-‘a‘+1]) f=0;
            else cnt[s[now]-‘a‘+1]=1;
            if (num==1) k=now-x+1;
            else
            {
                if (now-x+1!=k) f=0;
            }
            now++;
        }
        if (num!=3||!f)
        {
            cout<<"NO"<<endl;
        }
        else
        {
            cout<<"YES"<<endl;
        }
    }
    return 0;
}

Gunner

Accepts: 391 Submissions: 1397
Time Limit: 8000/4000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others)
问题描述
很久很久以前,有一个叫Jack的枪手。他非常喜欢打猎。一天,他去了一个小树林。那儿有n只鸟,还有n棵树。第i只鸟站在第i棵树的顶端。这些树从左到右排成一条直线。每一棵树都有它的高度。Jack站在最左边那棵树的左边。当Jack在高度为H的地方向右发射一棵子弹时,站在高度为H的树上的鸟儿就会落下来。
Jack会射击多次,他想知道每次射击会有多少鸟儿落下来。
输入描述
多组测试数据(大概5组),每一组的第一行给出n,m,n表示有n棵树和n只鸟,m表示Jack会射击m次。
在第二行,有n个整数, h[1],h[2],h[3],…,h[n]表示这些树的高度。
在第三行,有m个整数, q[1],q[2],q[3],…,q[m]表示Jack射击的高度。

[参数约定]
1≤n,m≤1000000(106)
1≤h[i],q[i]≤1000000000(109)
输出描述
对于每一个q[i],在一行中输出Jack射落了几只鸟。
输入样例
4 3
1 2 3 4
1 1 4
输出样例
1
0
1
Hint
大数据输入,推荐使用快速读读入。

我是用map水过的。

正解是将原来的树从高到低排序,然后每次询问二分查找一段区间。

注意在找到之后,要将其删掉。

#include <iostream>
#include <cstring>
#include <cmath>
#include <cstdio>
#include <cstdlib>
#include <algorithm>
#include <set>
#include <map>
using namespace std;
map<int,int> mp;
int n,m,cnt[1000010];
void read(int &tmp)
{
    int ch=getchar();
    int fu=1;
    tmp=0;
    for (;ch<‘0‘||ch>‘9‘;ch=getchar())
        if (ch==‘-‘) fu=-1;
    for (;ch>=‘0‘&&ch<=‘9‘;ch=getchar())
        tmp=tmp*10+ch-‘0‘;
    tmp*=fu;
}
int main()
{
    while (scanf("%d%d",&n,&m)!=EOF)
    {
        mp.clear();
        for (int i=1;i<=1000005;i++)
            cnt[i]=0;
        for (int i=1;i<=n;i++)
        {
            int x;
            read(x);
            if (!mp[x]) mp[x]=i;
            cnt[mp[x]]++;
        }
        for (int i=1;i<=m;i++)
        {
            int x;
            read(x);
            printf("%d\n",cnt[mp[x]]);
            cnt[mp[x]]=0;
        }
    }
    return 0;
}

Trees

Accepts: 156 Submissions: 533
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others)
问题描述
今天CodeFamer去坎树。有N棵树排成一排。他们被从1到N标号。第i号树的高度为hi。两棵未被坎掉的树编号分别为x,y当且仅当他们满足如下条件中一条时,他们是属于同一个块的:
1) x+1=y 或 y+1=x;
2) 存在一个棵未被坎掉的树,编号为z,x和z在同一个块并且y和z也在同一个块。
现在CodeFamer想要坎掉一些高度不大于某个值的树,坎掉之后会形成多少个块呢?
输入描述
多组测试数据(大概15组)
对于每一组数据,第一行包含两个整数N和Q,以一个空格分开,N表示有N棵树,Q表示有Q个查询。
在接下来的N行中,会出现h[1],h[2],h[3],…,h[N],表示N棵树的高度。
在接下来的Q行中,会出现q[1],q[2],q[3],…,q[Q]表示CodeFamerr查询。

请处理到文件末尾。

[参数约定]
1≤N,Q≤50000
0≤h[i]≤1000000000(109)
0≤q[i]≤1000000000(109)
输出描述
对于每一个q[i],输出CodeFamer坎掉高度不大于q[i]的树之后有多少个块。
输入样例
3 2
5
2
3
6
2
输出样例
0
2
Hint
在这个样例中,有3棵树,他们的高度依次是5 2 3。

对于6这个查询,如果CodeFamer坎掉高度不大于6的树,那么剩下的树高度形状是-1 -1 -1(-1表示那个树被坎掉了)。这样就有0个块。

对于2这个查询,如果CodeFamer坎掉高度不大于2的树,那么剩下的树高度形状是5 -1 3(-1表示那个树被坎掉了)。这样就有2个块。

思路题。

离线来做。

首先把树的标记ok[i]置为1,表示他们都没有被砍;
按照树高将读入排序,把询问也按照树高排序,当前的ans=1。

依次处理询问,由于询问是升序的,那么一定是按照当前树的顺序砍的。
当要砍掉第i棵树的时候,ok[i]=0,判断:
1.ok[i-1]=1,ok[i+1]=1,说明砍掉这棵树就会多一块,ans++

2.ok[i-1]=0,ok[i+1]=0,说明这棵树本来就是一块,砍掉之后ans–

3.ok[i-1]^ok[i+1]=1,砍掉这棵树对块数没有任何影响

#include <iostream>
#include <cmath>
#include <algorithm>
#include <cstdlib>
#include <cstring>
#include <cstdio>
using namespace std;
struct data
{
    int v,id,ans;
}h[50005],q[50005];
int n,Q,ok[50005];
void read(int &tmp)
{
    int ch=getchar();
    int fu=1;
    tmp=0;
    for (;ch<‘0‘||ch>‘9‘;ch=getchar())
        if (ch==‘-‘) fu=-1;
    for (;ch>=‘0‘&&ch<=‘9‘;ch=getchar())
        tmp=tmp*10+ch-‘0‘;
    tmp*=fu;
}
bool cmp(data a,data b)
{
    return a.v<b.v;
}
bool cmpp(data a,data b)
{
    return a.id<b.id;
}
int main()
{
    while (scanf("%d%d",&n,&Q)!=EOF)
    {
        ok[0]=0,ok[n+1]=0;
        for (int i=1;i<=n;i++)
            ok[i]=1,read(h[i].v),h[i].id=i;
        sort(h+1,h+1+n,cmp);
        for (int i=1;i<=Q;i++)
            read(q[i].v),q[i].id=i;
        sort(q+1,q+1+Q,cmp);
        int now=0;
        int ans=1;
        for (int i=1;i<=Q;i++)
        {
            while (h[now+1].v<=q[i].v&&now+1<=n)
            {
                int x=h[now+1].id;
                ok[x]=0;
                if (ok[x-1]&&ok[x+1]) ans++;
                if (!ok[x-1]&&!ok[x+1]) ans--;
                now++;
            }
            q[i].ans=ans;
        }
        sort(q+1,q+1+Q,cmpp);
        for (int i=1;i<=Q;i++)
            printf("%d\n",q[i].ans);
    }
    return 0;
}

The Monkey King

Accepts: 19 Submissions: 71
Time Limit: 8000/4000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others)
问题描述
就像大家所知道的,美猴王的名字叫孙悟空。他和他的后代们生活在花果山。一天,他的儿子得到了n个桃子。现在他们有m个猴子(包括悟空在内),他们被从1到m标号,悟空的号码是1。悟空想把这些桃子分给他们自己。由于悟空是大王,所以他获得的桃子必须是最多的。悟空想知道有多少种不同的分配方法。
例如n=2,m=3的时候,只有一种分法2 0 0。
当给定n,m时,你的任务是计算悟空可以有多少种不一样的方法来分配这些桃子。由于答案比较大输出对1000000007取余的结果即可。
输入描述
多组测试数据。在输入文件的第一行有一个整数T,表示有T组数据。
在接下来的T行,每行包含n和m。他们的含义在上边已经提到。

[Technical Specification]
所有输入均为整数。
1≤T≤25
1≤n,m≤100000
输出描述
对于每一个数据在一行中输出答案。
查看样例可以获得更多信息。
输入样例
2
2 2
3 5
输出样例
1
5
Hint
第二组样例中有5种分配方案,他们是
2 1 0 0 0
2 0 1 0 0
2 0 0 1 0
2 0 0 0 1
3 0 0 0 0

容斥原理+多重集的排列组合~

(前两天刚做过一道【BZOJ 1272】,考试却没想出来TT)

枚举悟空分得的桃子数为i,那么其他人分得的桃子数都要<i,求其他人分得桃子数<i的分法用容斥原理:

?(i)+(i)

如何计算有n?i个桃子分给m?1只猴子,其中有j只猴子分得的桃子i的分法?

首先选出j只猴子C(m?1,j),那么i?j个桃子已经有了归属。
问题变成了将n?i?i?j个桃子分给m?1只猴子,用隔板法!

桃子看成1,猴子看成0,相当于用m?2个0把n?i?i?j个1分成m?1段,即

C(n?i?i?j+m?2,m?2)

最后的答案就是

C(m?1,j)?C(n?i?i?j+m?2,m?2)

这样两层枚举看起来是O(n2)的复杂度,实际上是n+n2+n3+n4+?=nlogn的~

【bestcoder #36】ABCD题解

标签:bestcoder   思路题   容斥原理   排列组合   

原文地址:http://blog.csdn.net/regina8023/article/details/44893243

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!