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的分法)…
如何计算有
n−i
个桃子分给
m−1
只猴子,其中有
j
只猴子分得的桃子
首先选出
j
只猴子
问题变成了将
n−i−i∗j
个桃子分给
m−1
只猴子,用隔板法!
桃子看成1,猴子看成0,相当于用 m−2 个0把 n−i−i∗j 个1分成 m−1 段,即
最后的答案就是
这样两层枚举看起来是 O(n2) 的复杂度,实际上是 n+n2+n3+n4+⋯=nlogn 的~