不知不觉,又好久没写blog了,双管齐下,不免有点精力不足,但相信自己,相信队友,全力以赴,胜利就在前方
成功组队后的第一次真正意义上的个人cf,有压力,但确实也过于疏忽
A. Kirill And The Game
思路:告诉你分子与分母区间,分子分母均为整数,再给你一个整数,问你是否在该区间内
小心翼翼,判断区间端点,考虑到整数,转成double,担心精度丢失,加个eps还resubmit一次,为此扣了50分,心疼半天
后来无聊,还锁了自己的题,美滋滋去hack别人
到头来都没想到,整数规划问题,不仅仅是边界上的陷阱,中间也有值的缺漏,当队友被fst的那一刻,看到队友的代码,瞬间感受到了自己同样的命运
/*
Author Owen_Q
*/
#include <bits/stdc++.h>
using namespace std;
const int maxn = 1e5+10;
int main()
{
int l,r,x,y,k;
while(scanf("%d%d%d%d%d",&l,&r,&x,&y,&k)!=EOF)
{
double mink = double(l) / double(y);
double maxk = double(r) / double(x);
//cout << maxk << " " << mink <<" " << k<< endl;
if((maxk+1e-9)>=k&&(mink-1e-9)<=k)
{
int i;
for(i=l;i<=r;i++)
{
if(i%k==0)
{
printf("YES\n");
break;
}
}
if(i<=r)
{
continue;
}
}
printf("NO\n");
/*bool ok = false;
for(int i=l;i<=r;i++)
{
if(i%k==0&&x<=i/k&&y>=i/k)
{
ok = true;
break;
}
}
if(ok)
{
printf("YES\n");
}
else
{
printf("NO\n");
}*/
}
/*int l,r,x,y;
double k;
cin >> l >> r >> x >> y >> k;
if(l/y<=k&&k<=r/x)
cout<<"Y";
else
cout<<"N";*/
return 0;
}
B. Gleb And Pizza
思路:或许这才是这次比赛最水的一题了吧,根据圆的性质,判断顶点距离关系即可
/*
Author Owen_Q
*/
#include <bits/stdc++.h>
using namespace std;
const int maxn = 1e5+10;
int main()
{
int r,d;
while(scanf("%d%d",&r,&d)!=EOF)
{
int n;
scanf("%d",&n);
int sum = 0;
for(int i=0;i<n;i++)
{
int x,y,rr;
scanf("%d%d%d",&x,&y,&rr);
if(((x*x + y*y)>=(r-d+rr)*(r-d+rr))&&((x*x+y*y)<=(r-rr)*(r-rr)))
{
sum++;
}
}
printf("%d\n",sum);
}
return 0;
}
C. Ilya And The Tree
思路:找树上最大公约数,2e5的复杂度,O(n^2)的算法,本想到用最大公约数剪枝,将每点单独处理成已去点和未去点两类,但担心极端n个最大公约数,又是O(1e10)的复杂度,感觉会凉,殊不知,gcd具有下降性,且每次下降1/2,因此n个数的gcd最多只有log(n),set完美解决,因此,该算法复杂度实际为O(nlog(n))完全没问题
/*
Author Owen_Q
*/
#include <bits/stdc++.h>
using namespace std;
const int maxn = 2e5+10;
int a[maxn];
bool vis[maxn];
vector<int> ne[maxn];
int full[maxn];
set<int> nofull[maxn];
int gcd(int a,int b)
{
return b == 0 ? a : gcd(b, a % b);
}
void dfs(int la,int p)
{
//cout << "$$$" << p << "$$$"<<endl;
vis[p] = true;
full[p] = gcd(full[la],a[p]);
set<int> :: iterator it;
for(it = nofull[la].begin();it!=nofull[la].end();it++)
{
nofull[p].insert(gcd((*it),a[p]));
//cout << "-" << (*it) <<"-" <<gcd((*it),a[p])<<"-"<<a[p] << "-" << endl;
}
nofull[p].insert(full[la]);
//cout << "*-*-" << *(nofull[1].begin()) << endl;
vector<int> :: iterator itne;
for(itne = ne[p].begin();itne!=ne[p].end();itne++)
{
if(!vis[(*itne)])
{
dfs(p,(*itne));
}
}
return ;
}
int main()
{
int n;
//cout << gcd(0,5) << endl;;
while(scanf("%d",&n)!=EOF)
{
memset(vis,false,sizeof(vis));
ne[0].clear();
nofull[0].clear();
full[0] = 0;
ne[0].push_back(1);
for(int i=1;i<=n;i++)
{
scanf("%d",&a[i]);
ne[i].clear();
nofull[i].clear();
}
for(int i=1;i<n;i++)
{
int x,y;
scanf("%d%d",&x,&y);
ne[x].push_back(y);
ne[y].push_back(x);
}
dfs(0,1);
for(int i=1;i<n;i++)
{
//cout <<"**"<<*(nofull[i].begin())<<"*"<<*(nofull[i].rbegin()) << "***" << endl;
printf("%d ",max((*(nofull[i].rbegin())),full[i]));
}
printf("%d\n",max((*(nofull[n].rbegin())),full[n]));
}
return 0;
}
最后给个访问set首尾元素的小tip:
set <template T> a; 首元素 = * ( a.begin()); 尾元素 = * (a.rbegin());
D. Vitya and Strange Lesson
思路:这题确实难度不小,O(3e5)的查询,每次长度为3e5的mex数组异或与查找,确实不易操作
总查询次数肯定是定死无法操作的,因此想到优化每次查询与异或操作,看能不能将线性降到log级
于是想到二分,由于异或操作是按位的,又想到按位操作,最多19位,O(19*log(3e5))的时间复杂度是相当可观的
考虑到最高位的异或,只会将最大与最小两部分交换,于是二分,一步步缩小查询区间还是比较可行的
至于mex值的所在区间,利用数字标记,累加,来判断是否缺值
来自分治dalao队友的想法,确实很妙
据说这题还可以用trie树来做,对于数据结构渣渣的我来说还是算了吧
/*
Author Owen_Q
*/
#include <bits/stdc++.h>
using namespace std;
const int maxt = 1e6+10;
int t[maxt];
int main()
{
int n,m;
while(scanf("%d%d",&n,&m)!=EOF)
{
memset(t,0,sizeof(t));
for(int i=0;i<n;i++)
{
int a;
scanf("%d",&a);
t[a] = 1;
}
for(int i=1;i<=maxt-10;i++)
{
t[i] += t[i-1];
}
int p = 0;
while(m--)
{
int x;
scanf("%d",&x);
p ^= x;
int st = 0;
int fi = ((1<<19)-1);
for(int pos = 18;pos >= 0;pos--)
{
int mid = (st + fi) >> 1;
if(p & (1<<pos))
{
int di = t[fi]-t[mid];
if(di<fi-mid)
{
st = mid + 1;
}
else
{
fi = mid;
}
}
else
{
int di;
if(st>0)
{
di = t[mid] - t[st-1];
}
else
{
di = t[mid];
}
if(di<mid-st+1)
{
fi = mid;
}
else
{
st = mid+1;
}
}
}
printf("%d\n",st^p);
}
}
return 0;
}
明日第一场组队赛,加油,奋斗icpc/ccpc