Educational Codeforces Round 156 (Rated for Div. 2)
文章目录
A. Sum of Three
guess+数学 800
要找三个不同的数使得: x+y+z == n,并且每个数都无法被3整除
请问是否存在这样的三元组?
对于一个数,它模以3只有三种结果:0,1,2
如果这个数,被分成2个数a,b
那么a,b模以3也只有三种结果,0,1,2
现在我们要a,b模以3不等于0
所以我们直接让 a=2 b=n-2 那么判断一下 b>2 and b%3!=0 即可
或者 a=4 b=n-4 判断一下 b>4 and b%3!=0 即可
为什么取2和4? 因为2%3的余数是2,4%3的余数是1
#include<bits/stdc++.h>
using namespace std;
#define int long long
#define PII pair<int,int>
void slove(){
int n;
cin>>n;
n--;
if(n-2 > 2){
int r1=(n-2)%3;
if(r1!=0){
cout<<"YES"<<endl;
cout<<1<<' '<<2<<' '<<n-2<<endl;
return;
}
}
if(n-4>4 ){
int r1=(n-4)%3;
if(r1!=0){
cout<<"YES"<<endl;
cout<<1<<' '<<4<<' '<<n-4<<endl;
return;
}
}
cout<<"NO"<<endl;
}
signed main(){
int t;
cin>>t;
while(t--){
slove();
}
}
B. Fear of the Dark
二分+分类讨论 1200
从(0,0)开始一共有4种情况能到达 ( P x , P y ) (P_x,P_y) (Px,Py)
0—> a—>p
0—>b---->p
0---->a---->b---->p
0---->b----->a----->p
然后二分半径就行了。
可以提前算出来 0----a、0-----b、a-----b、a----p、b-----p 之间的距离
然后简单check就行了,当满足上面任意条件,mid缩小
否则mid变大
#include<bits/stdc++.h>
using namespace std;
#define int long long
#define PII pair<int,int>
void slove(){
PII p,a,b;
cin>>p.first>>p.second>>a.first>>a.second>>b.first>>b.second;
double lena= sqrt(pow(a.first,2)+pow(a.second,2));
double lenb=sqrt(pow(b.first,2)+pow(b.second,2));
double lenab=sqrt(pow(a.first-b.first,2)+pow(a.second-b.second,2));
double inf=1e-6;
double lenap=sqrt(pow(a.first-p.first,2)+pow(a.second-p.second,2));
double lenbp=sqrt(pow(b.first-p.first,2)+pow(b.second-p.second,2));
auto check=[&](double mid){
// 第一种情况,0->a->b->p
if(mid>=lena and 2*mid>=lenab and (mid>=lenbp or mid>=lenap)){
return 1;
}
// 0->b->a->p
if(mid>=lenb and 2*mid>=lenab and (mid>=lenbp or mid>=lenap) ){
return 1;
}
// 0->a->p
if(mid>=lena and mid>=lenap){
return 1;
}
//0->b->p
if(mid>=lenb and mid>=lenbp){
return 1;
}
return 0;
};
double l=0,r=1e9;
while(r-l>inf){
double mid=(l+r)/2;
if(check(mid))r=mid;
else l=mid;
}
printf("%.10lf\n",l);
}
signed main(){
int t;
cin>>t;
while(t--){
slove();
}
}
C. Decreasing String
字符串处理,贪心 1600
考虑一个问题: 对于一个字符串,我们只能删除一个字符,使得这个字符串的字典序最小。
我们应该怎么删除?
答案是,删除第一个逆序的字符即可。
暴力做法:
假如我们要获得第 k次的字符串,那么我们重复k次,每次将第一个遇到的逆序字符删除就行了。
对于我们要获得第几次的字符串,就需要从位置n入手,因为第0次的字符串,删除了0个字符,长度为s.size()
第k次的字符串,删除了k个字符,长度为s.size()-k
那么累加起来,你会发现是一个等差数列求和。
可以选择lower_bound查找前缀和,也可以不断减去s.size()-i
减到不能再减即可。
#include<bits/stdc++.h>
using namespace std;
#define int long long
#define PII pair<int,int>
void slove(){
string s;
cin>>s;
int len=s.size();
int pos;
cin>>pos;
int sum=0;
int cnt=0; //记录pos在第几个字符串
for(int i=1;i<=len;i++){
sum+=(len-i+1);
if(pos<=sum){
cnt=i;
sum-=(len-i+1);
break;
}
}
int yu=pos-sum; //在第cnt个字符串中的位置
// cout<<cnt<<endl;
int bnt=1; //当前迭代到第几个字符串
string t;
for(int i=0;i<s.size();i++){
t+=s[i];
while(bnt<cnt and t.back()>s[i+1] and t.size() and i!=s.size()-1 ){
t.pop_back();
bnt++;
}
}
cout<<t[yu-1];
}
signed main(){
int t;
cin>>t;
while(t--){
slove();
}
}