Skip the Class
Accepts: 678
Submissions: 1285
Time Limit: 2000/1000 MS (Java/Others)
Memory Limit: 65536/65536 K (Java/Others)
问题描述
终于又开学啦。呃喵最喜欢的就是开学了,因为这样她又可以愉快地翘课了(啊?) 呃喵接下来有n节课程需要上(换句话说,可以翘。) 每节课程有相应的课程类型与课程翘课价值。 有一点需要注意的是,呃喵不可以翘同一类课程超过两次,就是如果这类课已经翘了两次,接下来就一定要上。 问你在这个条件下,呃喵可以获得的最大翘课价值。
输入描述
第一行为一个整数T,代表数据组数。 接下来,对于每组数据—— 第一行一个整数n,表示接下来需要依次上的课程数量, 接下来有n行,每行包括一个仅由'a'~'z'构成的长度不超过10的字符串s与一个正整数v。 其中字符串表示课程的类型,相同的字符串代表相同的课程。 数据保证—— 1 <= T <= 1000 对于每组数据,1 <= n <= 100,1 <= |s| <= 10, 1 <= v <= 1000
输出描述
对于每组数据,输出一行。 该行有1个整数,表示呃喵可以获得的最大翘课价值。
输入样例
2 5 english 1 english 2 english 3 math 10 cook 100 2 a 1 a 2
输出样例
115 3
对课程排个序,取前两名即可。
#include <iostream>
#include<bits/stdc++.h>
using namespace std;
const int N=1100;
struct node
{
int v;
char s[20];
}a[N];
bool cmp(node a,node b)
{
if(strcmp(a.s,b.s)==0)
{
return a.v>b.v;
}
return strcmp(a.s,b.s)<0;
}
int main()
{
int T;
scanf("%d",&T);
while(T--)
{
int n;
scanf("%d",&n);
for(int i=0;i<n;i++)
{
scanf("%s%d",a[i].s,&a[i].v);
}
sort(a,a+n,cmp);
int t;
int ans=0;
for(int i=0;i<n;i++)
{
if(i==0||strcmp(a[i].s,a[i-1].s)!=0)
{
ans+=a[i].v;
t=1;
}
else if(strcmp(a[i].s,a[i-1].s)==0&&t<2)
{
t++;
ans+=a[i].v;
}
}
cout<<ans<<endl;
}
}
Count the Sheep
Accepts: 227
Submissions: 805
Time Limit: 3000/1500 MS (Java/Others)
Memory Limit: 65536/65536 K (Java/Others)
问题描述
开学翘课固然快乐,然而也有让呃喵抓狂的事,那当然就是考试了!这可急坏了既要翘课又想要打BC还要准备考试的呃喵。 呃喵为了准备考试没有时间刷题,想打BC又不想跌分,只得求助于BCround92的出题人snowy_smile,让他说点什么 ~~>_<~~。 snowy_smile实在没有办法,但是又不好意思透题,只好告诉呃喵,当务之急是好好休息。 "如果你按照下面这个办法睡着,那么第二天就绝对不会在BC的赛场上跌分—— 想象一片一望无际、广阔无边的青青草原,草原上住着一群羊,包括n只沉默的男羊和m只流泪的女羊,在男羊和女羊之间,存在k个朋友关系。 现在你可以以任意一只羊为起点,顺着朋友关系数下去。如果能够连续数4只各不相同的羊,就能超过99%的数羊者,成功入睡。" 呃喵听后十分震惊,但她还是听话地数下去,果然,数到第4只羊就睡着了,并一口气睡过了头,成功地错过了第二天的BestCoder,真的不会在BC的赛场上跌分啦! 然而你,可就没有这么好的运气了,你既然看到了这第二题,自然一般已有提交,已经无法回头了。 面对"不AC这题就可能跌分"窘境的你,需要说出,呃喵在睡前可能有多少种不同的数羊序列。 即输出"A-B-C-D"这样序列的方案数,满足A-B、B-C、C-D是朋友关系且A、B、C、D各不相同。
输入描述
第一行输入数据组数T 对于每组数据,第一行有三个整数n, m, k,表示n只男羊编号分别为1~n,m只女羊编号分别为1~m,并且存在k个朋友关系。 接下来给出k行,每行给出两个数x y,表示第x只男羊和第y只女羊是朋友。 数据保证—— 不会给出重复的朋友关系 1 <= T <= 1000 对于30%的数据,1 <= n, m, k <= 100 对于99%的数据,1 <= n, m, k <= 1000 对于100%的数据,1 <= n, m, k <= 100000
输出描述
对于每组数据,输出一行,该行包含一个整数,表示呃喵睡觉前可能数了哪4只羊的序列的方案数。
输入样例
(为了方便阅读,样例输入中数据组间中会额外添加一行空行) 3 2 2 4 1 1 1 2 2 1 2 2 3 1 3 1 1 2 1 3 1 3 3 3 1 1 2 1 2 2
输出样例
8 0 2
Hint
第一组样例:(b1-g1-b2-g2) (b1-g2-b2-g1) (b2-g1-b1-g2) (b2-g2-b1-g1) (g1-b1-g2-b2) (g1-b2-g2-b1) (g2-b1-g1-b2) (g2-b2-g1-b1) 共8种合法序列
公羊和母羊构成一个二分图,而遍历四只不同的羊需要连续的三条线段。考虑三条线段中间的那条线段,连接两端的端点a、b,(a的度-1)*(b的度-1)等于这条线段能取得的方案数。遍历所有的关系, 把它们作为中间线段考虑即可。最后的答案*=2。时间复杂度为o(k),比题解好一些……
#include <iostream>
#include<bits/stdc++.h>
#define ll __int64
using namespace std;
const int N=110000;
int dl[N],dr[N],l[N],r[N];
int main()
{
int T;
scanf("%d",&T);
while(T--)
{
int n,m,k;
scanf("%d%d%d",&n,&m,&k);
memset(dl,0,sizeof(dl));
memset(dr,0,sizeof(dr));
for(int i=0;i<k;i++)
{
scanf("%d%d",&l[i],&r[i]);
dl[l[i]]++;
dr[r[i]]++;
}
ll ans=0;
for(int i=0;i<k;i++)
{
ll ld=dl[l[i]],rd=dr[r[i]];
ans+=(ld-1)*(rd-1);
}
ans*=2;
printf("%I64d\n",ans);
}
}
Girls Love 233
Accepts: 30
Submissions: 218
Time Limit: 2000/1000 MS (Java/Others)
Memory Limit: 65536/65536 K (Java/Others)
问题描述
除了翘课以外,结识新的妹子也是呃喵重要的日程安排之一。 这不,呃喵又混进了一个叫做ACgirls的女生群里,来达成自己不可描述的目的。 然而,呃喵只会喵了个咪地说话,于是很容易引起注意。为了掩饰自己的真实身份,呃喵每次说话都小心翼翼。 她知道,很多女生都喜欢说"233",然而呃喵想说的话一开始就确定好了,所以她要对这句话做修改。 这句话的长度为n,语句里的字符不是'2'就是'3'。 呃喵的智力非常有限,只有m点。她每次操作可以交换两个相邻的字符,然而代价是智力-2。 现在问你,在使得自己智力不降为负数的条件下,呃喵最多能使这个字符串中有多少个子串"233"呢? 如"2333"中有一个"233","232323"中没有"233"
输入描述
第一行为一个整数T,代表数据组数。 接下来,对于每组数据—— 第一行两个整数n和m,分别表示呃喵说的字符串长度 以及呃喵的智力 第二行一个字符串s,代表呃喵具体所说的话。 数据保证—— 1 <= T <= 1000 对于99%的数据,1 <= n <= 10, 0 <= m <= 20 对于100%的数据,1 <= n <= 100, 0 <= m <= 100
输出描述
对于每组数据,输出一行。 该行有1个整数,表示最多可使得该字符串中有多少个"233"
输入样例
3 6 2 233323 6 1 233323 7 4 2223333
输出样例
2 1 2
这题场上爆搜T了,之后用题解的方法过了:
首先,因为字符不是'2'就是'3',所以我们可以把字符串当做一个全部都是'3'的串,然后有若干的'2'插入到了某些位置。
显然,我们交换相邻的'2'与'2'或者相邻的'3'与'3'是没有意义的,我们只会进行相邻'2'与'3'之间的交换。因此,所有'2'的相对前后关系其实是不会变化的。
做了这些比较基础的分析之后,基于数据规模很小,我们可以用以下4个要素表示完整的状态:
1.处理到第几个'2'
2.最后一个'2'停留在什么位置,如果当前的'2'与上一个'2'距离相差>=2时则对答案+1
3.呃喵的剩余交换次数是多少
4.当前已经成功得到几个"233"
而这四个要素的大小,最坏情况下分别是n、n、m、n级别的数,我们随便以3个要素作为下标对应状态,使得第4个要素最优做DP. 转移的时候步长也是不超过2m的,所以很容易就可以得出复杂度为O(n * n * m/2 * m)的算法,这个对于本题的时限和数据,没有什么作死写法的话是可以完全无压力顺利AC的。
显然,我们交换相邻的'2'与'2'或者相邻的'3'与'3'是没有意义的,我们只会进行相邻'2'与'3'之间的交换。因此,所有'2'的相对前后关系其实是不会变化的。
做了这些比较基础的分析之后,基于数据规模很小,我们可以用以下4个要素表示完整的状态:
1.处理到第几个'2'
2.最后一个'2'停留在什么位置,如果当前的'2'与上一个'2'距离相差>=2时则对答案+1
3.呃喵的剩余交换次数是多少
4.当前已经成功得到几个"233"
而这四个要素的大小,最坏情况下分别是n、n、m、n级别的数,我们随便以3个要素作为下标对应状态,使得第4个要素最优做DP. 转移的时候步长也是不超过2m的,所以很容易就可以得出复杂度为O(n * n * m/2 * m)的算法,这个对于本题的时限和数据,没有什么作死写法的话是可以完全无压力顺利AC的。
题解说的第二个优化方法感觉可行,在标程的代码上感觉处理的有点疑问(没看懂- -),所以放弃了。
#include <iostream>
#include<bits/stdc++.h>
using namespace std;
const int N=105;
int n,T,m,cnt2,f[N][N][N],g[N];
char s[N];
int v[N][N][N];//ʡȥmemset
int dfs(int num2,int lastpos,int lastm)
{//cout<<num2<<" "<<lastpos<<" "<<lastm<<endl;
if(num2 > cnt2) return n-lastpos >= 2;
if(v[num2][lastpos][lastm] == T + 1) return f[num2][lastpos][lastm];
v[num2][lastpos][lastm] = T + 1;
int l = max(lastpos + 1,g[num2] - lastm);
int r = min(n,g[num2] + lastm);
f[num2][lastpos][lastm] = -1e9;
for(int i = l;i <= r;i++)
{
int cost = abs(i - g[num2]);
int t = dfs(num2 + 1,i,lastm - cost)+(i - lastpos >= 3) * (num2 > 1);
if(t > f[num2][lastpos][lastm])
f[num2][lastpos][lastm] = t;
}
return f[num2][lastpos][lastm];
}
int main()
{
scanf("%d",&T);
while(T--)
{
scanf("%d%d",&n,&m);
m /= 2;
scanf("%s",s + 1);
cnt2 = 0;
for(int i = 1; i <= n; i++)
{
if(s[i] == '2')
{
g[++cnt2] = i;
}
}
if(cnt2 == 0) printf("0\n");
else printf("%d\n",dfs(1,0,m));
}
}
总体来说这场不难,但是太久没写题,思维不太够用。掉分伤心。