Codeforces Round #412 (Div. 2, base on VK Cup 2017 Round 3)
比赛时过了3题,rating暴涨90+。。一定是上次只做出一题拉低了rating。。这场感觉AB都是题面杀。。然后比赛时看了DE感觉都可做,赛后补了一下。
官方题解依旧是高质量,耐心读,即使是会的题,也绝对收获不少。样例代码也很棒。
官方题解传送门:%tourist
Codeforces 807A Is it rated?
题意
绝对的题面杀,反正我比赛时没读懂,只是按样例写了一发碰巧过了。大致意思是说,现在有一场CF比赛,按这场比赛打得由好到坏给你个表,第一列是这场比赛之前大家的分数(rating),第二列是这场比赛之后大家的分数(rating)。问你这场比赛是否计入排名。
思路
rating的含义:一场比赛下来,假设A打的比B好。比赛前,假设B的rating比A高,那么比赛后,A的rating不一定比B高,但是A的rating增量肯定比B高。
所以如果比赛前后有人Rating发生呢过了变化,那么肯定是rated比赛。如果比赛前后没人的rating的变化,且rating不是严格单调的。那肯定是unrated的比赛。否则就是maybe。
代码
#include <cstdio>
#include <cstdlib>
#include <iostream>
#include <algorithm>
#include <string>
#include <cstring>
#include <vector>
#include <cmath>
#include <queue>
#include <stack>
#include <set>
#include <map>
#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=10000+7;
const int oo=0x3f3f3f3f;
typedef long long LL;
const LL loo=4223372036854775807ll;
typedef long double LB;
const LL mod=1e9+7;
int ra[1005];
int main()
{
_;
int n;
while(cin>>n)
{
bool flag=false;
for(int i=0;i<n;i++)
{
cin>>ra[i]>>ra1[i];
if(ra[i]!=ra1[i])
{
flag=true;
}
}
bool flag1=false;
if(flag==false)
{
for(int i=1;i<n;i++)
{
if(ra[i-1]<ra[i])
{
flag1=true;
break;
}
}
}
if(flag==true)
{
cout<<"rated"<<endl;
}
else
{
if(flag1==false)
{
cout<<"maybe"<<endl;
}
else
{
cout<<"unrated"<<endl;
}
}
}
return 0;
}
Codeforces 807B T-Shirt Hunt
题意
题面杀。。给你三个数abc,现在我的分数是b,我是rank1,我预计至少分数不能低于c分才是rank1。我的id是a,那么我要hack多少次才能拿到T桖。那到T桖的人的id根第一名的分数有关。具体公式看原文吧。
思路
读懂题就很简单了,暴力枚举就行。
代码
#include <cstdlib>
#include <iostream>
#include <algorithm>
#include <string>
#include <cstring>
#include <vector>
#include <cmath>
#include <queue>
#include <stack>
#include <set>
#include <map>
#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=10000+7;
const int oo=0x3f3f3f3f;
typedef long long LL;
const LL loo=4223372036854775807ll;
typedef long double LB;
const LL mod=1e9+7;
vector<int> res;
int main()
{
_;
LL n;
while(cin>>n)
{
LL now, low;
cin>>now>>low;
LL pre=now;
bool flag=false;
while(now>=low)
{
LL ti=(now/50)%475;
for(int i=0;i<25;i++)
{
ti=(ti*96+42)%475;
if(n==ti+26)
{
flag=true;
break;
}
}
if(flag) break;
now-=50;
}
if(!flag)
{
now=pre;
while(1)
{
LL ti=(now/50)%475;
for(int i=0;i<25;i++)
{
ti=(ti*96+42)%475;
if(n==ti+26)
{
flag=true;
break;
}
}
if(flag) break;
now+=50;
}
}
LL tt=now-pre;
if(tt>0)
{
tt=(tt+50)/100;
}
else
{
tt=0;
}
cout<<tt<<endl;
}
return 0;
}
Codeforces 807C Success Rate
题意
我现在的ac题目是x,总提交是y。我想达到的正确率是p/q,问至少需要提交多少题才能达到我想要的正确率。
思路
因为pq互质,所以要想达到正确率,可以将pq都扩大n倍,得到 npnq 。正确的题数是np,错误的题是nq-np,分别大于x与y-x即可。另外还有logn的二分,因为不等式是单调的,所以可以二分n。官方题解写的很详细。
代码
#include <cstdio>
#include <cstdlib>
#include <iostream>
#include <algorithm>
#include <string>
#include <cstring>
#include <vector>
#include <cmath>
#include <queue>
#include <stack>
#include <set>
#include <map>
#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=10000+7;
const int oo=0x3f3f3f3f;
typedef long long LL;
const LL loo=4223372036854775807ll;
typedef long double LB;
const LL mod=1e9+7;
vector<int> res;
int main()
{
_;
LL n;cin>>n;
while(n--)
{
LL x, y, p, q;
cin>>x>>y>>p>>q;
if(q==p&&x<y)
cout<<-1<<endl;
else if(x>0&&p==0)
cout<<-1<<endl;
else
{
LL a=y-x;
LL b=q-p;
LL c=ceil(1.0*a/b);
c=max(c, (LL)ceil(1.0*x/p));
cout<<c*q-y<<endl;
}
}
return 0;
}
Codeforces 807D Dynamic Problem Scoring
题意
CF过题的分数计算是动态的,每道题总分与过了这题人数与参与比赛(有过submit)的人数之比有关。另外你的得分还与你ac的时间有关。
然后现在假设所有参与者的过题时间(某题没过时间就是-1),给你了,再也不会有变化。有个作弊者(0号),他注册了很多小号,他可以让他的小号提交正确/错误的sunmit来改变某题的分数。注意如果他没过某题,他的小号不能提交正确的submit。问他要想分数比1号人高,他至少需要多少个小号。
思路
乍一看很乱,看了题解自习想想,情况很少。
1. 首先,一道题X,如果他没过,对手过了,那么他想最小化总分,他不应该提交这题。
2. 如果他与对手都没过或者过的时间一样,那么他也不应该管,因为没用。
3. 如果他过得时间比对手早,那么他想最大化总分,他应该提交错误的submit。
4. 如果他过得比对手晚,他应该提交正确的submit。
现在枚举小号数。注意枚举小号数时,我们是假设这些小号都存在了,所以不需要考虑错误的提交了。只需要找出需要进行正确提交的题,并提交。在计算总分,看他是否超过了对手。从小枚举到大,保证了我们不用考虑提交错误答案。
所以是否存在某种情况,他的小号只应该提交错误的submit,不能提交正确的submit,而按照上面的分析,又没有可以让他提交错误submit的题,这样我们的程序就gg了?
我开始也困在这了。仔细想想,按照上面的分析,这种情况只能发生在他所有题都比对手晚。这样他是永远不可能超过对手的。而我们的代码不会让他的小号提交题,自然他也永远不可能超过对手。
枚举小号数到什么时候停止呢?n最大120,只要到31*n,保证所有题都到了最大份即可。
看代码吧,或者写一遍。我就是写着写着就明白了。
代码
#include <cstdio>
#include <cstdlib>
#include <iostream>
#include <algorithm>
#include <string>
#include <cstring>
#include <vector>
#include <cmath>
#include <queue>
#include <stack>
#include <set>
#include <map>
#define _ ios_base::sync_with_stdio(0),cin.tie(0)
#define M(a,b) memset(a,b,sizeof(a))
#define N n
using namespace std;
const int MAXN=10000+7;
const int oo=0x3f3f3f3f;
typedef long long LL;
const LL loo=4223372036854775807ll;
typedef long double LB;
const LL mod=1e9+7;
int t1[6];
int t2[6];
int speo[6];
int judge(int sov, int sub)
{
if(32*sov<=sub) return 3000;
else if(16*sov<=sub) return 2500;
else if(8*sov<=sub) return 2000;
else if(4*sov<=sub) return 1500;
else if(2*sov<=sub) return 1000;
else return 500;
}
int main()
{
_;
int n;
while(cin>>n)
{
M(t1, 0);M(t2, 0);M(speo, 0);
for(int i=0;i<n;i++)
{
if(i==0) cin>>t1[1]>>t1[2]>>t1[3]>>t1[4]>>t1[5];
else if(i==1) cin>>t2[1]>>t2[2]>>t2[3]>>t2[4]>>t2[5];
else
{
int q;
for(int j=0;j<5;j++)
{
cin>>q;
if(q!=-1) speo[j+1]++;
}
}
}
for(int i=1;i<=5;i++)
{
if(t1[i]!=-1) speo[i]++;
else t1[i]=250;
if(t2[i]!=-1) speo[i]++;
else t2[i]=250;
}
int res;
for(res=0;res<3840;res++)
{
int mark1=0, mark2=0;
int sump=n+res;
for(int j=1;j<=5;j++)
{
int tmpsepo=0;
if(t1[j]==250)
{
}
else if(t1[j]<t2[j])
{
}
else if(t1[j]>=t2[j])
{
tmpsepo=res;
}
mark1+=(judge(speo[j]+tmpsepo, sump)*(250-t1[j])/250);
mark2+=(judge(speo[j]+tmpsepo, sump)*(250-t2[j])/250);
}
if(mark1>mark2) break;
}
cout<<(res==3840 ? -1 : res)<<endl;
}
return 0;
}
Codeforces 807E Prairie Partition
题意
思路
读入一个数,判断他是整数次幂还是有余数,分别存到power和between里。注意到序列最大数量一定是1的个数,且答案是连续的,所以只需要求出最小的序列个数,二分左端点。二分的时候判断一下 即可。
代码
#include <cstdio>
#include <cstdlib>
#include <iostream>
#include <algorithm>
#include <string>
#include <cstring>
#include <vector>
#include <cmath>
#include <queue>
#include <stack>
#include <set>
#include <map>
#define _ ios_base::sync_with_stdio(0),cin.tie(0)
#define M(a,b) memset(a,b,sizeof(a))
#define N n
#define max3(a,b,c) std::max(a,std::max(b,c))
using namespace std;
const int MAXN=10000+7;
const int oo=0x3f3f3f3f;
typedef long long LL;
const LL loo=4223372036854775807ll;
typedef long double LB;
const LL mod=1e9+7;
int power[70+10];
int between[70+10];
int sy[70+10];
int xl[70+10];
int main()
{
_;
int n;
while(cin>>n)
{
M(power, 0);M(between, 0);M(sy, 0);M(xl, 0);
//int mp=0;
for(int i=0;i<N;i++)
{
LL t;cin>>t;
int p=0;bool fl=false;
while(t>1)
{
if(t&1) fl=true;
t=t>>1;p++;
}
if(fl) between[p]++;
else power[p]++;
//if(!fl) mp=max(mp, p);
}
int l=1, r=power[0]+1;
while(l<r)
{
int mid=(l+r)/2;
int now=mid;
for(int i=0;i<=70;i++)
{
sy[i]=power[i]-now;
int tnow=now;
if(power[i+1]<tnow)
{
tnow=power[i+1];
}
xl[i]=now-tnow;
now=tnow;
}
bool fl=false;
int tt=0;
for(int i=70;i>=0;i--)
{
tt+=xl[i];
tt-=between[i];
tt-=sy[i+1];
if(tt<0) { fl=true;break; }
}
tt-=sy[0];
if(tt<0) { fl=true; }
if(fl)
{
l=mid+1;
}
else
{
r=mid;
}
}
if(l<=power[0])
{
for(int i=l;i<=power[0];i++)
{
cout<<i<<' ';
}
cout<<endl;
}
else cout<<-1<<endl;
}
return 0;
}