Nordic Collegiate Programming Contest (NCPC 2021)(SMU 2024 ICPC网络赛选拔赛)
Nordic Collegiate Programming Contest (NCPC 2021)(SMU 2024 ICPC网络赛选拔赛)
A Antenna Analysis
思路
原式可拆成:
\[(x_i-x_j)-c(i-j)=(x_i-c\cdot i)+(-x_j+c\cdot j)
\]
分别维护下两个的最大值即可。
代码
#include<bits/stdc++.h> #define int long long #define ll __int128 const int mod= 998244353; #define PII pair<int,int> #define PIII pair<int,PII> #define INF 0x3f3f3f3f #define double long double using ull = std::uint64_t; #define endl '\n' #pragma GCC optimize(2) using namespace std; priority_queue<int,vector<int>,less<int>>q1; priority_queue<int,vector<int>,less<int>>q2; void solve() { int n,c; cin>>n>>c; for(int i=1;i<=n;i++){ int x; cin>>x; q1.push(c*i-x); q2.push(c*i+x); if(i>1){ cout<<max(q1.top()+x-c*i,q2.top()-x-c*i)<<" \n"[i==n]; }else{ cout<<0<<" \n"[i==n]; } } } int32_t main() { std::ios::sync_with_stdio(false); cin.tie(0); cout.tie(0); int T = 1; // cin >> T; while (T--) { solve(); } return 0; }
C Customs Controls
思路
隔得久有点忘了,大致思路就是,从起点和它所连的边都染同一个色,这样就可以封死这些路,假设有 \(x\) 条出路只能染 \(y\) 条,那么剩下的 \(x-y\) 条我们可以找到终点对应的这 \(x-y\) 条,然后把它们和终点又染同一个色,这样就可以把剩下的 \(x-y\) 条也封死。
建议画图手玩一下,只有 \(n=2,k=1\) 这种情况是 impossible
。
代码
#include<bits/stdc++.h> #define ll long long #define int long long const int mod= 998244353; #define PII pair<ll,int> #define PIII pair<int,PII> #define endl '\n' #pragma GCC optimize(2) using namespace std; const int N=1e6+3; vector<int>g[N]; int dist[N]; int a[N]; void solve() { int n, m, k; cin >> n >> m >> k; for (int i = 1; i <= n; ++i) { dist[i] = LLONG_MAX / 2; } for (int i = 1; i <= n; ++i) { cin >> a[i]; } for (int i = 0; i < m; ++i) { int x, y; cin >> x >> y; g[x].push_back(y); g[y].push_back(x); } if (n == 2 and k == 1) { cout << "impossible\n"; return; } dist[1] = a[1]; priority_queue<PII, vector<PII >, greater<PII>> q; vector<int> vis(n + 1); q.push({dist[1], 1}); while (q.size()) { auto [w, u] = q.top(); q.pop(); if (vis[u])continue; vis[u] = 1; for (auto v: g[u]) { if (dist[v] > w + a[v]) { dist[v] = w + a[v]; q.push({dist[v], v}); } } } vector<int> f[n + 1], tu[n + 1]; fill(vis.begin(), vis.end(), 0); queue<int> p; p.push(n); while (p.size()) { auto dq = p.front(); p.pop(); vis[dq] = 1; for (auto v: g[dq]) { if (dist[v] + a[dq] == dist[dq]) { f[dq].push_back(v); f[v].push_back(dq); tu[v].push_back(dq); if (vis[v])continue; vis[v] = 1; p.push(v); } } } fill(vis.begin(), vis.end(), 0); vector<char> ans(n + 1, '.'); int x, y; auto puts = [&]() { for (int i = 1; i <= n; ++i) { if (ans[i] == '.') { if (x) { x--; ans[i] = 'N'; } else { y--; ans[i] = 'S'; } } cout << ans[i]; } }; int cnt = 0; for (int i = 1; i <= n; ++i) { if (f[i].size()) { cnt++; } } x = k, y = n - k; if (k > n - k) { x = k, y = n - k; ////x为N,Y为S ///X大 int ax = f[1].size(); int bx = f[n].size(); if (ax + 1 <= x) { ans[1] = 'N'; vis[1] = 1; queue<int> q; for (auto v: f[1]) { ans[v] = 'N'; vis[v] = 1; q.push(v); } x -= ax + 1; puts(); return; } if (bx + 1 <= x) { ans[n] = 'N'; vis[n] = 1; queue<int> q; for (auto v: f[n]) { ans[v] = 'N'; vis[v] = 1; q.push(v); } x -= bx + 1; puts(); return; } } else { x = k, y = n - k; ////x为N,Y为S ///Y大 int ax = f[1].size(); int bx = f[n].size(); if (ax + 1 <= y) { ans[1] = 'S'; vis[1] = 1; queue<int> q; for (auto v: f[1]) { ans[v] = 'S'; vis[v] = 1; q.push(v); } y -= ax + 1; puts(); return; } if (bx + 1 <= y) { ans[n] = 'S'; vis[n] = 1; queue<int> q; for (auto v: f[n]) { ans[v] = 'S'; vis[v] = 1; q.push(v); } y -= bx + 1; puts(); return; } } if (x) { ans[1] = 'N'; x--; } for (auto v: f[1]) { if (x) { ans[v] = 'N'; x--; } else { ans[v] = 'S'; y--; } } puts(); return; } int32_t main() { std::ios::sync_with_stdio(false); cin.tie(0); int T = 1; // cin >> T; while (T--) { solve(); } return 0; }
D Deceptive Directions
思路
因为给出的是最短到达宝藏的指令,所以宝藏一定是距离起点 S
长度为 \(s.size()\) 的地方。
又因为每一步都是错误指令,那么每一步都有其他三个方向的可能,按照每步三个方向去 BFS,最后判断到达的距离是否和指令长度相等即可。
细节部分需要好好处理,比如 BFS 时超过了指令的长度等。
代码
#include<bits/stdc++.h> #define ll long long #define int long long const int mod= 998244353; #define PII pair<ll,int> #define PIII pair<int,PII> #define endl '\n' #pragma GCC optimize(2) using namespace std; const int N=1e6+3; const int maxn=1009; int dx[4]={-1,1,0,0}; int dy[4]={0,0,-1,1}; void solve() { int n, m; cin >> m >> n; string s; vector<vector<char>> g(n, vector<char>(m)); vector<vector<int>> dist(n, vector<int>(m, INT_MAX)); vector<vector<int>> dist2(n, vector<int>(m, INT_MAX)); vector<vector<int>> vis(n, vector<int>(m, 0)); queue<PII > q; int stx, sty; for (int i = 0; i < n; ++i) { for (int j = 0; j < m; ++j) { cin >> g[i][j]; if (g[i][j] == 'S') { stx = i, sty = j; } } } cin>>s; dist[stx][sty] = 0; q.push({stx, sty}); while (q.size()) { auto [x, y] = q.front(); q.pop(); for (int i = 0; i < 4; ++i) { int nx = x + dx[i]; int ny = y + dy[i]; if (nx < 0 or nx >= n or ny < 0 or ny >= m)continue; if (g[nx][ny] == '#')continue; if (dist[nx][ny] > dist[x][y] + 1) { dist[nx][ny] = dist[x][y] + 1; q.push({nx, ny}); } } } dist2[stx][sty]=0; q.push({stx,sty}); while(q.size()){ auto [x,y]=q.front(); q.pop(); vis[x][y]=1; int d=dist2[x][y]; if(d>=s.size())continue; if(s[d]=='N'){ d=0; } else if(s[d]=='S'){ d=1; } else if(s[d]=='W'){ d=2; } else { d=3; } for (int i = 0; i <4 ; ++i) { if(i==d)continue; int nx=x+dx[i]; int ny=y+dy[i]; if (nx < 0 or nx >= n or ny < 0 or ny >= m)continue; if (g[nx][ny] == '#')continue; if(vis[nx][ny])continue; if(dist2[x][y]+1==dist[nx][ny]){ dist2[nx][ny]=dist[nx][ny]; vis[nx][ny]=1; q.push({nx,ny}); } } } for (int i = 0; i <n ; ++i) { for (int j = 0; j <m ; ++j) { if(dist2[i][j]==s.size()){ g[i][j]='!'; } } } for (int i = 0; i <n ; ++i) { for (int j = 0; j <m ; ++j) { cout<<g[i][j]; } cout<<endl; } } int32_t main() { std::ios::sync_with_stdio(false); cin.tie(0); int T = 1; // cin >> T; while (T--) { solve(); } return 0; }
G Grazed Grains
思路
求圆面积并。
队友写的圆面积交,然后求 \(1\sim n\) 的圆的交的和。
也可以用自适应辛普森乱搞,比如洛谷这道圆面积并模板题CIRU - The area of the union of circles - 洛谷),直接把AC代码放在这题上即可通过。
(圆面积交求圆面积并)代码
#include<bits/stdc++.h> #define ll long long #define int long long const int mod= 998244353; #define PII pair<ll,int> #define PIII pair<int,PII> #define endl '\n' #pragma GCC optimize(2) using namespace std; const int N=1e6+3; const int maxn=1009; const double eps=1e-8; const double pi= acos(-1); int dcmp(double x){ return fabs(x)<eps?0:(x<0?-1:1); } struct circle{ double x,y,r,angle; int d; circle(){} circle(double x,double y,double angle=0,int d=0) :x(x),y(y),angle(angle),d(d) {} }; typedef circle Circle; circle cir[maxn],tp[maxn<<1]; double area[maxn]; double sqr(double x){ return x*x; } double dis(circle a,circle b){ return sqrt(sqr(a.x-b.x)+sqr(a.y-b.y)); } double cross(circle a,circle b,circle c){ return (b.x-a.x)*(c.y-a.y)-(b.y-a.y)*(c.x-a.x); } int CirCrossCir(Circle p1,double r1,Circle p2 ,double r2,Circle &cp1,Circle&cp2) { double mx = p2.x - p1.x, sx = p2.x + p1.x, mx2 = mx * mx; double my = p2.y - p1.y, sy = p2.y + p1.y, my2 = my * my; double sq = mx2 + my2, d = -(sq - sqr(r1 - r2)) * (sq - sqr(r1 + r2)); if(d+eps<0 )return 0; if(d<eps)d=0; else d=sqrt(d); double x=mx*((r1+r2)*(r1-r2)+mx*sx)+sx*my2; double y=my*((r1+r2)*(r1-r2)+my*sy)+sy*mx2; double dx=mx*d,dy=my*d; sq*=2; cp1.x=(x-dy)/sq; cp1.y=(y+dx)/sq; cp2.x=(x+dy)/sq; cp2.y=(y-dx)/sq; if(d>eps)return 2; else return 1; } bool circmp(const Circle& u,const Circle& v){ return dcmp(u.r-v.r)<0; } bool cmp(const Circle& u,const Circle& v){ if(dcmp(u.angle-v.angle)){ return u.angle<v.angle; } return u.d>v.d; } double calc(Circle cir,Circle cp1,Circle cp2){ double ans=(cp2.angle-cp1.angle)*sqr(cir.r) - cross(cir,cp1,cp2)+ cross(Circle(0,0),cp1,cp2); return ans/2; } void CirUnion(Circle cir[],int n){ Circle cp1,cp2; sort(cir,cir+n,circmp); for (int i = 0; i <n ; ++i) { for (int j = i+1; j <n ; ++j) { if(dcmp(dis(cir[i],cir[j])+cir[i].r-cir[j].r)<=0){ cir[i].d++; } } } for (int i = 0; i <n ; ++i) { int tn=0,cnt=0; for (int j = 0; j <n ; ++j) { if(i==j)continue; if(CirCrossCir(cir[i],cir[i].r,cir[j],cir[j].r,cp2,cp1)<2)continue; cp1.angle=atan2(cp1.y-cir[i].y,cp1.x-cir[i].x); cp2.angle=atan2(cp2.y-cir[i].y,cp2.x-cir[i].x); cp1.d=1; tp[tn++]=cp1; cp2.d=-1; tp[tn++]=cp2; if(dcmp(cp1.angle-cp2.angle)>0){ cnt++; } } tp[tn++]=Circle (cir[i].x-cir[i].r,cir[i].y,pi,-cnt); tp[tn++]=Circle (cir[i].x-cir[i].r,cir[i].y,-pi,cnt); sort(tp,tp+tn,cmp); int p,s=cir[i].d+tp[0].d; for (int j = 1; j <tn ; ++j) { p=s; s+=tp[j].d; area[p]+= calc(cir[i],tp[j-1],tp[j]); } } } int n; void solve() { ::scanf("%lld",&n); for (int i = 0; i <n ; ++i) { ::scanf("%lf%lf%lf",&cir[i].x,&cir[i].y,&cir[i].r); // ::printf("%f %f %f",cir[i].x,cir[i].y,cir[i].r); cir[i].d=1; } ::memset(area,0,sizeof area); CirUnion(cir,n); double ans=0; for (int i = 1; i <=n ; ++i) { area[i]-=area[i+1]; ans+=area[i]; } ::printf("%.10lf\n",ans); } int32_t main() { // std::ios::sync_with_stdio(false); // cin.tie(0); int T = 1; // cin >> T; while (T--) { solve(); } return 0; }
(自适应辛普森)代码
#include <bits/stdc++.h> using namespace std; using i64 = long long; const double eps = 1e-8; // 根据题目精度要求进行修改 const double PI = acos(-1.0); // pai, 3.1415916.... const int N = 2024; struct seg { double l, r; friend bool operator <(seg a, seg b) { if (a.l == b.l) return a.r < b.r; return a.l < b.l; } }; struct vec { i64 x, y; }; double dis(vec a, vec b) { return sqrt(1.0 * (a.x - b.x) * (a.x - b.x) + 1.0 * (a.y - b.y) * (a.y - b.y)); } struct cir { vec o; i64 r; friend bool operator <(cir a, cir b) { return a.r < b.r; } } a[N]; int n; vector<seg> v; int st, ed; double f(double x) { //求f(x) v.clear(); for (int i = st; i <= ed; ++i) { //处理出交点的纵坐标,保存为线段 if (x > a[i].o.x + a[i].r || x < a[i].o.x - a[i].r) continue; double l = x - a[i].o.x; l = sqrt(a[i].r * a[i].r - l * l); v.push_back((seg) {a[i].o.y - l, a[i].o.y + l}); } if (v.empty()) return 0.0; sort(v.begin(), v.end()); //以下贪心线段覆盖 double ans = 0, last = v[0].l; for (int i = 0; i < v.size(); ++i) { if (v[i].r > last) { ans += v[i].r - max(last, v[i].l); last = v[i].r; } } return ans; } double calc(double l, double r, double sl, double sr) { //直接计算一段区间的面积 double mid = (l + r) / 2; return (r - l) * (sl + 4.0 * f(mid) + sr) / 6.0; } double simpson(double l, double r, double S, double sl, double sr) { double mid = (l + r) / 2, s = f(mid); double t1 = calc(l, mid, sl, s), t2 = calc(mid, r, s, sr); if (fabs(t1 + t2 - S) < eps) return S; return simpson(l, mid, t1, sl, s) + simpson(mid, r, t2, s, sr); } void init() { //预处理,删除被包含的圆 int cnt = 0; for (int i = 1, j; i <= n; ++i) { for (j = i + 1; j <= n; ++j) { if (a[i].r - a[j].r + dis(a[i].o, a[j].o) < eps) { break; } } if (j > n) a[++cnt] = a[i]; } n = cnt; } bool cmp(cir a, cir b) { //按圆的最左端排序,用于判断连续相交 return a.o.x - a.r < b.o.x - b.r; } double ans; void solve() { //寻找每段联通的圆,进行计算 double l, r; int i = 1, j; while (i <= n) { l = a[i].o.x - a[i].r, r = a[i].o.x + a[i].r; for (j = i + 1; j <= n; ++j) { if (a[j].o.x - a[j].r > r) break; r = max(r, (double)a[j].o.x + a[j].r); } st = i, ed = j - 1, i = j; double mid = (l + r) / 2; ans += simpson(l, r, f(mid), f(l), f(r)); } } int main() { ios::sync_with_stdio(false); cin.tie(nullptr); cin >> n; for (int i = 1; i <= n; i ++) { int x, y, r; cin >> x >> y >> r; a[i] = {x, y, r}; } sort(a + 1, a + n + 1); init(); sort(a + 1, a + n + 1, cmp); solve(); cout << fixed << setprecision(3) << ans << '\n'; return 0; }
J Joint Jog Jam
思路
直接计算,队友写的,已经眼花缭乱了
代码
#include<bits/stdc++.h> #define int long long #define ll __int128 const int mod= 998244353; #define PII pair<int,int> #define PIII pair<int,PII> #define INF 0x3f3f3f3f #define double long double using ull = std::uint64_t; #define endl '\n' #pragma GCC optimize(2) using namespace std; void solve() { int x[5],y[5]; for(int i=1;i<=4;i++){ cin>>x[i]>>y[i]; } int a,b,c; c=(x[1]-x[2])*(x[1]-x[2])+(y[1]-y[2])*(y[1]-y[2]); b=2*((x[1]-x[2])*(x[2]+x[3]-x[1]-x[4])+(y[1]-y[2])*(y[2]+y[3]-y[1]-y[4])); a=(x[2]+x[3]-x[1]-x[4])*(x[2]+x[3]-x[1]-x[4])+(y[2]+y[3]-y[1]-y[4])*(y[2]+y[3]-y[1]-y[4]); double mx=0; if(a!=0)mx=(double)(4*a*c-b*b)/4.0/a; mx=max(mx,1.0L*(x[1]-x[2])*(x[1]-x[2])+(y[1]-y[2])*(y[1]-y[2])); mx=max(mx,1.0L*(x[3]-x[4])*(x[3]-x[4])+(y[3]-y[4])*(y[3]-y[4])); cout<< fixed << setprecision(10)<<sqrtl(mx)<<endl; } int32_t main() { std::ios::sync_with_stdio(false); cin.tie(0); cout.tie(0); int T = 1; // cin >> T; while (T--) { solve(); } return 0; }
K Knot Knowledge
思路
排序后比较第一个不同的即可,否则输出最后一个。
代码
#include<bits/stdc++.h> #define int long long #define ll __int128 const int mod= 998244353; #define PII pair<ll,int> #define PIII pair<int,PII> #define INF 0x3f3f3f3f #define double long double using ull = std::uint64_t; #define endl '\n' #pragma GCC optimize(2) using namespace std; vector<int>q1,q2; void solve() { int n; cin>>n; for(int i=1;i<=n;i++){ int x; cin>>x; q1.push_back(x); } for(int i=1;i<n;i++){ int x; cin>>x; q2.push_back(x); } sort(q1.begin(),q1.end()); sort(q2.begin(),q2.end()); for(int i=0;i<n-1;i++){ if(q1[i]!=q2[i]){ cout<<q1[i]<<endl; return; } } cout<<q1[n-1]<<endl; } int32_t main() { std::ios::sync_with_stdio(false); cin.tie(0); cout.tie(0); int T = 1; // cin >> T; while (T--) { solve(); } return 0; }
L Locust Locus
思路
找 \(c_1,c_2\) 的最小公倍数加上年份即可。
代码
#include <bits/stdc++.h> using namespace std; using i64 = long long; int main() { ios::sync_with_stdio(false); cin.tie(nullptr); int n; cin >> n; int ans = INT_MAX / 2; for (int i = 0; i < n; i ++) { int y, c1, c2; cin >> y >> c1 >> c2; ans = min(ans, y + lcm(c1, c2)); } cout << ans << '\n'; return 0; }
本文作者:Ke_scholar
本文链接:https://www.cnblogs.com/Kescholar/p/18450115
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
分类:
标签:
,
,
,
,
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步