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;
}
posted @ 2024-10-07 15:08  Ke_scholar  阅读(8)  评论(0编辑  收藏  举报