Codeforces Round #404 div2 题解
数学专场?
传送门:HustOJ
传送门:官方题解以及官方hint还是很给力的,比如我的D题
CodeForces 785A Anton and Polyhedrons
题意,思路
太水了。。。
代码
#include <cstdio>
#include <cstdlib>
#include <iostream>
#include <algorithm>
#include <string>
#include <cstring>
#include <vector>
#include <cmath>
#include <queue>
#include <stack>
#include <map>
#include <set>
#define _ ios_base::sync_with_stdio(0),cin.tie(0)
#define M(a,b) memset(a,b,sizeof(a))
using namespace std;
const int MAXN=800;
const int oo=0x3f3f3f3f;
typedef long long LL;
const LL loo=4223372036854775807ll;
typedef long double LB;
const LL mod=1e9+7;
int main()
{
_;
int n;
while(cin>>n)
{
LL sum=0;
for(int i=0;i<n;i++)
{
string s;cin>>s;
if(s[0]=='T') sum+=4;
else if(s[0]=='C') sum+=6;
else if(s[0]=='O') sum+=8;
else if(s[0]=='D') sum+=12;
else if(s[0]=='I') sum+=20;
}
cout<<sum<<endl;
}
return 0;
}
CodeForces 785B Anton and Classes
题意
有两种课各n,m节,接下来给你n节课的起止时间,m节课的起止时间。这人要上两种课各一节,问你他在两种课中间休息时间最长能到多长。
思路
不难。四个变量,分别记录第一种课最晚开始与最早结束的时间,第二种课最晚开始和最早结束的时间,比一下,就能确定先上那种课,以及最长休息时间。
注意数据范围,反正我直接LL。
代码
#include <cstdio>
#include <cstdlib>
#include <iostream>
#include <algorithm>
#include <string>
#include <cstring>
#include <vector>
#include <cmath>
#include <queue>
#include <stack>
#include <map>
#include <set>
#define _ ios_base::sync_with_stdio(0),cin.tie(0)
#define M(a,b) memset(a,b,sizeof(a))
using namespace std;
const int MAXN=800;
const int oo=0x3f3f3f3f;
typedef long long LL;
const LL loo=4223372036854775807ll;
typedef long double LB;
const LL mod=1e9+7;
int main()
{
_;
int n;
while(cin>>n)
{
LL m1=0, m2=loo, m3=0, m4=loo;
for(int i=0;i<n;i++)
{
LL a, b;cin>>a>>b;
m1=max(m1, a);m2=min(m2, b);
}
int m;cin>>m;
for(int i=0;i<m;i++)
{
LL a, b;cin>>a>>b;
m3=max(m3, a);m4=min(m4, b);
}
LL t1, t2;
if(m2<m3) t1=m3-m2;
else t1=0;
if(m4<m1) t2=m1-m4;
else t2=0;
cout<<max(t1, t2)<<endl;
}
return 0;
}
CodeForces 785C Anton and Fairy Tale
题意
一个粮仓,容量n。最开始是满的,以后每天会填进去m的米,如果溢出,那么实际存米量还是n。第i天会有i只麻雀,每只吃1米,共吃i米。问哪天麻雀吃完米后粮仓第一次出现空。至于边界判定的问题,看原题吧。
思路
比较烦人的题。。。官方的hint说手工模拟计算,的确。。
首先,如果n<=m,那么肯定是第n天。
如果n>m,那么第m+1天填过米,粮仓肯定是最后一次满的。之后粮仓不在会满。这样就可以考虑每天麻雀先吃,第二天在填米之后的净减少量。这个值从1开始增大。停止的条件是,某一天的米不够吃了,这样当天吃过米后,粮仓第一次出现空。
设m天后过了k天:
列出方程:
n−k∗(k+1)2<m+k
求满足条件的最小正整数k。
关于这个方程,在y轴右侧是单调递增的。求根公式啊,二分啊都行。
代码
求根公式搞完了,注意k要>0
#include <cstdio>
#include <cstdlib>
#include <iostream>
#include <algorithm>
#include <string>
#include <cstring>
#include <vector>
#include <cmath>
#include <queue>
#include <stack>
#include <map>
#include <set>
#define _ ios_base::sync_with_stdio(0),cin.tie(0)
#define M(a,b) memset(a,b,sizeof(a))
using namespace std;
const int MAXN=800;
const int oo=0x3f3f3f3f;
typedef long long LL;
const LL loo=4223372036854775807ll;
typedef long double LB;
const LL mod=1e9+7;
int main()
{
//_;
LL n;
while(cin>>n)
{
LL m;cin>>m;
LL res;
if(n<=m) res=n;
else
{
res=m+1;
LL k=((-3+sqrt(9+4*(2*n-2*m-2)))/2);
while(k*k+3*k-(2*n-2*m-2)<0) k++;
res+=k;
}
cout<<res<<endl;
}
return 0;
}
CodeForces 785D Anton and School - 2
题意
读原题吧。。题意里面有概念,我很迷。。
大体是,给你一串括号,让你找一个长度为非零偶数子串,满足一半左括号一半右括号。
思路
很好的一道组合数学题。。在永刚大佬的帮助下做出来的。。。还是那句话,官方的hint挺不错的。
官方说先看这种子串:((())))),就是前面全是左括号,后面跟的全是右括号的。这种串的做法其实跟普通串一样。
做法是:先统计每个右括号前面的左括号数,记为l[i],i表示在原string中的位置。在统计每个右括号后面的右括号数r[i]。
比如((())))),l数组:00033333,r数组:00043210。然后我们看第一个),l=3,r=4。右括号以他为首的括号子串个数:
然后发现,对于一个l值是a,r值是b的右括号,它贡献的结果是:
用组合数公式化简。。膜永刚大佬。。:
然后。。膜永刚大佬说这相当于,两堆球,一堆a个一堆b个,从里面一共取出b+1个的取法。。结果就是 Cb+1a+b
注意组合数比较大,预处理一下逆表在计算。
代码
#include <cstdio>
#include <cstdlib>
#include <iostream>
#include <algorithm>
#include <string>
#include <cstring>
#include <vector>
#include <cmath>
#include <queue>
#include <stack>
#include <map>
#include <set>
#define _ ios_base::sync_with_stdio(0),cin.tie(0)
#define M(a,b) memset(a,b,sizeof(a))
using namespace std;
const int MAXN=200005;
const int oo=0x3f3f3f3f;
typedef long long LL;
const LL loo=4223372036854775807ll;
typedef long double LB;
const LL mod=1e9+7;
string ss;
int l[MAXN];
int r[MAXN];
LL fact[MAXN];
LL inv[MAXN];
LL f[MAXN];
void pre()
{
//MOD是要模的数
//fact是阶乘取模表,inv是阶乘的逆取模
M(fact, 0);M(inv, 0);M(f, 0);
const LL MOD=mod;
fact[0]=1;
f[0]=1;
inv[0]=1;
fact[1]=1;
f[1]=1;
inv[1]=1;
for(int i=2;i<MAXN;i++)
{
fact[i]=(LL)(fact[i-1]*i)%MOD;
f[i]=(LL)(MOD-MOD/i)*f[MOD%i]%MOD;
inv[i]=(LL)inv[i-1]*f[i]%MOD;
}
}
LL CMOD(LL a, LL b)
{
if(b>a) return 0;
if(b==a) return 1;
LL res=0;
res=(((fact[a]*inv[b])%mod)*inv[a-b])%mod;
return res;
}
int main()
{
_;
pre();
M(l, 0);M(r, 0);
while(cin>>ss)
{
int n=ss.size();
int pre=0;
for(int i=0;i<n;i++)
{
if(ss[i]==')')
{
l[i]=pre;
}
else pre++;
}
pre=0;
for(int i=n-1;i>=0;i--)
{
if(ss[i]==')')
{
r[i]=pre;pre++;
}
}
LL sum=0;
for(int i=0;i<n;i++)
{
if(ss[i]==')')
{
sum=(sum+CMOD(l[i]+r[i], r[i]+1))%mod;
}
}
cout<<sum<<endl;
}
return 0;
}