Gym 101964 2018-2019 ACM-ICPC Southeastern European Regional Programming Contest (SEERC 2018)
传送门
A.Numbers
B.Broken Watch
先考虑最简单的情况,就是a,b,c都相等的情况,这个时候答案显然只会跟n有关系,在n个线段里面选3个的情况就是C(n,3),其中有一部分不合法,这个时候考虑怎样是不合法的,现在设取三条边分别是x,y,z;当x经过y到达z的这个角的角度小于180度的时候,那么这个方案必然是不合法的,这样的话只需要确定x和z就可以确定一族不可行的方案,x和z可以夹1....[n/2](上取整)条边,也就是形成了[n/2](上取整)族答案,每一族的方案数分别是1...[n/2]。于是用总的方案数减去(1+2+3+...+[n/2](上取整))即可。这里的答案是对2^64取模,因此统计答案时要处理一下除法。 对于a,b,c不相等的情况直接乘上A(3,1)或A(3,3)即可 #include<bits/stdc++.h> using namespace std; typedef unsigned long long ll; int main(){int a,b,c;ll n;scanf("%d%d%d%llu",&a,&b,&c,&n);ll tmp=(n+1)/2;tmp-=2;ll ans=0;//特判除以6的情况ll tmp1=n,tmp2=n-1,tmp3=n-2;if(tmp1%2==0) tmp1/=2;else if((tmp2)%2==0) tmp2/=2;if(tmp1%3==0) tmp1/=3;else if(tmp2%3==0) tmp2/=3;else if(tmp3%3==0) tmp3/=3;ans=tmp1*tmp2*tmp3;ans-=n*(tmp*(tmp+1)/2);if(a!=b&&b!=c&&c!=a){//全都不相同ans*=6;}else if(a!=b||a!=c||b!=c){//有一个不同ans*=3;}printf("%llu\n",ans);return 0; } View Code
C.Tree
首先,题目中的”使得最大值最小“这句话就非常符合二分的条件了。因此我们考虑对答案(两个黑点的最远的距离)进行二分。
现在就要考虑如何进行check。
对于每一个二分值k,我们考虑先用bfs遍历整颗树,然后利用bfs的性质(距离当前点的所有已bfs过且小于等于d的那些点,他们之间两两距离也小于等于k),找出满足距离等于k的对应的一个个点集。之后我们可以用dfs去遍历这些点集,判断点集中的黑点的个数与需要选取的黑点个数m之间的关系即可(如果数量>=n,则右指针左移动;反之左指针右移)。
#include <bits/stdc++.h> #define maxn 105 using namespace std; vector<int>vec[maxn]; int vis[maxn];//用vis数组去区分点的不同的集合 int a[maxn]; queue<int>que; int n,m; int ans=0; int dfs(int now,int fa,int all,int dis){int res=a[now];if(dis==all) return res;for(auto &it:vec[now]){if(!vis[it]||it==fa) continue;res+=dfs(it,now,all,dis+1);}return res; } bool check(int k){//二分的check,本质上为一个bfsmemset(vis,0,sizeof(vis));while(!que.empty()) que.pop();que.push(1);while(!que.empty()){//bfs选取部分点集int now=que.front();que.pop();vis[now]=1;int tmp=dfs(now,0,k,0);//通过dfs获取这个集合的黑点的个数if(tmp>=m) return 1;for(auto &it:vec[now]){if(vis[it]) continue;que.push(it);}}return 0; } int main() {//freopen("in.txt","r",stdin);scanf("%d%d",&n,&m);for(int i=1;i<=n;i++) scanf("%d",&a[i]);for(int i=0;i<n-1;i++){int from,to;scanf("%d%d",&from,&to);vec[from].push_back(to);vec[to].push_back(from);}int l=0,r=n;while(l<r){int mid=(l+r)>>1;if(check(mid)) r=mid;else l=mid+1;//cout<<l<<" "<<r<<endl; }cout<<r<<endl; } View Code
D.Space Station
E.Fishermen
我们可以先把渔夫的位置排个序,然后遍历所有的鱼,每一条鱼能够被可以被抓都在x轴有一个范围,通过二分,在渔夫中找到最左的和最右的,然后差分一下,最后求个前缀和就可以得出答案
#include <bits/stdc++.h> using namespace std; typedef long long ll; const int maxn=2e5+7; struct SS{int x,y; }a[maxn]; struct S{int x,id,idd;bool operator <(const S &bb)const {return x<bb.x;} }b[maxn]; int sum[maxn],ans[maxn]; int main(){//freopen("in.txt","r",stdin);int n,m,l;scanf("%d %d %d",&n,&m,&l);for (int i=1;i<=n;i++)scanf("%d %d",&a[i].x,&a[i].y);for (int i=1;i<=m;i++) {scanf("%d",&b[i].x);b[i].id=i;}sort(b+1,b+m+1);for (int i=1;i<=m;i++) b[i].idd=i;for (int i=1;i<=n;i++){if (a[i].y-l>0) continue;S tmp;tmp.x=a[i].x-l+a[i].y;int xx=lower_bound(b+1,b+m+1,tmp)-b;tmp.x=a[i].x+l-a[i].y;int yy=upper_bound(b+1,b+m+1,tmp)-b;sum[xx]++;sum[yy]--;}for (int i=1;i<=m;i++){sum[i]+=sum[i-1];ans[b[i].id]=sum[b[i].idd];}for (int i=1;i<=m;i++) printf("%d\n",ans[i]);return 0; } View Code
F.Min Max Convert
G.Matrix Queries
H.Modern Djinn
I.Inversion
首先,我们要把原序列还原,根据逆序对的性质,还原出原序列。接着,根据题意两个对集合的定义,可以知道选出的那个点集是从左到右升序的,且点集中最小的点在序列中左边没有比它更小的点,最大的点在序列中右边没有比它更大的点,所以我们可以进行dp,dp[i]表示以i为点集最后一个点的答案的数量。
dp转移见代码
J.Rabbit vs Turtle
K.Points and Rectangles
转载于:https://www.cnblogs.com/Chen-Jr/p/9879980.html
总结
以上是生活随笔为你收集整理的Gym 101964 2018-2019 ACM-ICPC Southeastern European Regional Programming Contest (SEERC 2018)的全部内容,希望文章能够帮你解决所遇到的问题。
- 上一篇: 缓存设计--读写锁场景实现
- 下一篇: HTTP协议、HTTP请求方法、常见状态