Codeforces Round #403 (Div. 2) B 二分或三分 D 2-sat E 思维,dfs
Codeforces Round #403 (Div. 2, based on Technocup 2017 Finals)
B. The Meeting Place Cannot Be Changed
题意:n个人,各自在点x[i],每个人最大速度v[i],可以往左右两个方向走。要使这n个人在同一个点相聚,求最小时间。
tags:可以直接三分位置,有个坑,eps取1e-7竟然会超时,取1e-6就过了;另外三分也不知道怎么搞出单调性的,貌似大家都是“显然”,23333。。也可以二分时间求交集,但在求交集时有点技巧,不断比较出左界最大值a和右界最小值b,看最后是否有a<=b
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
// 二分 #include<bits/stdc++.h> using namespace std; #pragma comment(linker, "/STACK:102400000,102400000") #define rep(i,a,b) for (int i=a;i<=b;i++) #define per(i,b,a) for (int i=b;i>=a;i--) #define mes(a,b) memset(a,b,sizeof(a)) #define INF 0x3f3f3f3f typedef long long ll; const int N = 60005; int n, x[N], v[N]; bool check(double t) { double minn=2000000005, maxn=0; rep(i,1,n) { minn=min(minn, x[i]+v[i]*t); maxn=max(maxn, x[i]-v[i]*t); } return maxn<=minn; } int main() { scanf("%d", &n); rep(i,1,n) scanf("%d", &x[i]); rep(i,1,n) scanf("%d", &v[i]); double l=0, r=1000000005, ans; while(fabs(r-l)>1e-7) { double mid=(l+(r-l)/2); if(check(mid)) r=mid, ans=mid; else l=mid; } printf("%.12f\n", ans); return 0; }
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
// 三分 #include<bits/stdc++.h> using namespace std; #pragma comment(linker, "/STACK:102400000,102400000") #define rep(i,a,b) for (int i=a;i<=b;i++) #define per(i,b,a) for (int i=b;i>=a;i--) #define mes(a,b) memset(a,b,sizeof(a)) #define INF 0x3f3f3f3f typedef long long ll; const int N = 60005; int n; double x[N], v[N]; double cal(double xi) { double res=0; rep(i,1,n) res=max(res, fabs(xi-x[i])/v[i]); return res; } int main() { scanf("%d", &n); rep(i,1,n) scanf("%lf", &x[i]); rep(i,1,n) scanf("%lf", &v[i]); double l=0, r=1000000005; while(fabs(r-l)>1e-6) { double m1=l+(r-l)/3, m2=r-(r-l)/3; double t1=cal(m1), t2=cal(m2); if(t1<t2) r=m2; else l=m1; } printf("%.12f\n", cal(l)); return 0; }
D. Innokenty and a Football League
题意:每个团队有两个单词s1,s2,有两种取名字的方法:1、a=s1[0]+s1[1]+s1[2];2、a'=s1[0]+s1[1]+s2[0]。限制:每个团队名字不能相同,而且,如果一个团队以第二种方法取名a',其它团队就不能以第一种方法取名a。求是否可能给每个团队都取名。
tags:第一次写2-sat,强行码了一发。。这题还有用贪心的,但感觉好玄
每个团队都只能在2种可能里选一种,而各个团队的可能又会互相影响,即裸的2判定性问题。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include<bits/stdc++.h> using namespace std; #pragma comment(linker, "/STACK:102400000,102400000") #define rep(i,a,b) for (int i=a;i<=b;i++) #define per(i,b,a) for (int i=b;i>=a;i--) #define mes(a,b) memset(a,b,sizeof(a)) #define INF 0x3f3f3f3f typedef long long ll; const int N = 200005; int n, m, k, tot, head[N]; string s[3]; map<string, int >mp; map<int , string>pm; struct Club{int fir, sec;}a[N]; struct Edge{int to, next;}e[N]; void Addedge(int u, int v){e[++tot].to=v, e[tot].next=head[u], head[u]=tot;} bool vis[N]; int Stack[N], top; bool dfs(int u) { if(vis[u^1]) return false; if(vis[u]) return true; vis[u]=true; Stack[top++]=u; for(int i=head[u]; i; i=e[i].next) if(dfs(e[i].to)==0) return false; return true; } bool Twosat(int n) //n { memset(vis,false,sizeof(vis)); for(int i=0; i<n; i+=2) { //i+=2 if(vis[i] || vis[i^1]) continue; top=0; if(dfs(i)==0) { while(top) vis[Stack[--top]]=false; //记录路径 if(dfs(i^1)==0) return false; //如果矛盾返回flase } } return true; } int main() { scanf("%d", &n); rep(i,1,n) { cin>>s[1]>>s[2]; string s1=s[1].substr(0,3); string s2=s[1].substr(0,2)+s[2][0]; if(mp[s1]==0) mp[s1]=++k, pm[k]=s1; if(mp[s2]==0) mp[s2]=++k, pm[k]=s2; a[i].fir=mp[s1], a[i].sec=mp[s2]; } rep(i,1,n) rep(j,1,n) { //加边,不太理解 if(i==j) continue; if(a[i].fir==a[j].fir) Addedge(2*i-2, 2*j-1), Addedge(2*i-1, 2*j-1); if(a[i].fir==a[j].sec) Addedge(2*i-2, 2*j-2); if(a[i].sec==a[j].fir) Addedge(2*i-1, 2*j-1); if(a[i].sec==a[j].sec) Addedge(2*i-1, 2*j-2); } if(Twosat(2*n)) { //2*n puts("YES"); rep(i,0,2*n-1) if(vis[i]) { if((i+1)&1) cout<<pm[a[(i+2)/2].fir]<<endl; else cout<<pm[a[(i+1)/2].sec]<<endl; } } else { puts("NO"); } return 0; }
题意:n个点m条无向边k个人,每个人每秒可以走过一条边。每个人最多可以经过 2n/k 个点(可重复),要使得最终n个点都至少被一个人遍历过,求每个人的路径走法。
tags:考思维,想不到啊mdzz
因为每个人最多可经过2n/k个点,k个人即最多可经过2n个点。这样的话,我们可以按dfs序搜一遍,把所有结点(包括dfs中重复的)都记录下来,再分配给这k个人即可。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include<bits/stdc++.h> using namespace std; #pragma comment(linker, "/STACK:102400000,102400000") #define rep(i,a,b) for (int i=a;i<=b;i++) #define per(i,b,a) for (int i=b;i>=a;i--) #define mes(a,b) memset(a,b,sizeof(a)) #define INF 0x3f3f3f3f typedef long long ll; const int N = 200005; int n, m, k, path[N<<1], cnt; //路径要开双倍 bool vis[N]; vector<int >G[N]; void dfs(int u) { vis[u]=1; path[++cnt]=u; for(auto v : G[u]) { if(vis[v]) continue; dfs(v); path[++cnt]=u; } } int main() { scanf("%d %d %d", &n, &m, &k); int u, v; rep(i,1,m) { scanf("%d %d", &u, &v); G[u].push_back(v); G[v].push_back(u); } dfs(1); int num=(2*n+k-1)/k, len; rep(i,1,k) { len=min(num, cnt); if(len==0) { printf("1 1\n"); continue; } printf("%d ", len); for(int i=0; i<len && cnt; i++, cnt--) printf("%d ", path[cnt]); puts(""); } return 0; }