ACL Contest 1(补题)

Posted 佐鼬Jun

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了ACL Contest 1(补题)相关的知识,希望对你有一定的参考价值。

A - Reachable Towns

题目链接: link.

题意:

在二维坐标轴给定 N N N个点,每个点都可以跳向向 x 和 y x和y xy值比它大或者 x 和 y x和y xy值比它小的点,现在让你输出每个点可以跳的最多的点数(自己也可以跳自己).

思路:

可以在每个跳的点对之间连一条边,代表这对点可以相互跳,把所有点都连完边后,每一个连通块内的点,一定是可以相互跳的,所以连通块的大小就是这个连通块每个点可以跳的最多点数。这个可以通过并查集实现,但不能每两个点之间判断一下是否能跳,时间复杂度太高,为 O ( n 2 ) O(n^2) O(n2),可以利用单调栈来降低时间复杂度,先按照 x x x的值升序排序,然后单调栈内维护的是,并查集内 y y y值的最小值,即单调栈内的值是单调递减的。每次取出来的点,取出来值如果在栈顶点的右上方,就把它与栈顶点结合成一个集合,并把栈顶弹出,然后再次判断。最后知道栈空,或者该点在栈顶点的右下角,即无法相互跳,那么此时就把这个点放进栈中。最后输出每个点所在并查集的大小,就是每个点可以跳的最多点数。

#include <bits/stdc++.h>
using namespace std;
const int N = 2e5 + 10;
const int inf = 0x3f3f3f3f;
typedef pair<int, int> PII;

struct node 
    int x, y, id;
 a[N];
int n;
int Size[N], fa[N];
PII sta[N];
int tt;
bool cmp(node a, node b)  return a.x < b.x; 
int find(int x) 
    if (x != fa[x]) fa[x] = find(fa[x]);
    return fa[x];

int main() 
    cin >> n;
    for (int i = 0, x, y; i < n; i++) 
        cin >> x >> y;
        a[i] = x, y, i;
    

    for (int i = 0; i < n; i++) 
        fa[i] = i, Size[i] = 1;
    
    sort(a, a + n, cmp);
    for (int i = 0; i < n; i++) 
        if (tt == 0) 
            sta[++tt] = a[i].id, a[i].y;
         else 
            int minv = a[i].y;
            while (tt && a[i].y > sta[tt].second) 
                minv = min(minv, sta[tt].second);
                int x = find(a[i].id), y = find(sta[tt].first);
                if (x != y) 
                    fa[x] = y;
                    Size[y] += Size[x];
                
                tt--;
            
            sta[++tt] = a[i].id, minv;
        
    
    for (int i = 0; i < n; i++) 
        cout << Size[find(i)] << endl;
    

B - Sum is Multiple

题目链接: link.

题意:

给定一个数字 N N N,现在让你找到一个最小的 k k k,让 1 + 2 + . . . . + k 1+2+....+k 1+2+....+k N N N的倍数,也就是说这个和能整除 N N N
思路:
把原式处理一下,就是 k ( k + 1 ) 2 = α N \\frack(k+1)2=αN 2k(k+1)=αN,即 k ( k + 1 ) = 2 α N k(k+1)=2αN k(k+1)=2αN,也就是说 2 × N ∣ k × ( k + 1 ) 2×N|k×(k+1) 2×Nk×(k+1)
下面的 n n n就代替 2 × N 2×N 2×N现在令 s = k × ( k + 1 ) s=k×(k+1) s=k×(k+1),使 n n n s s s质因数分解,就变成了 n = ∏ p i k i n=\\prod p_i^k_i n=piki s = ∏ p j k j s=\\prod p_j^k_j s=pjkj
对于 ∀ i ∀i i , p i k i ∣ s p_i^k_i|s pikis,又可以观察到 k 和 k + 1 k和k+1 kk+1互质,所以对于一部分 i i i p i k i ∣ k p_i^k_i|k pikik p i k i ∣ ( k + 1 ) p_i^k_i|(k+1) piki(k+1)

所以可以枚举 n n n的因数 a 和 b a和b ab,即 a × b = n a×b=n a×b=n g c d ( a , b ) = 1 gcd(a,b)=1 gcd(a,b)=1 k = a x k=ax k=ax, k + 1 = b y k+1=by k+1=by,所以 b y − a x = 1 by-ax=1 byax=1,而这个式子可以由 e x g c d exgcd exgcd扩展欧几里得算出来,用扩展欧几里得算 b y + a x ′ = 1 by+ax'=1 by+ax=1,这个式子的解,算出 x 和 y x和y xy,看 x 和 y x和y xy那个是负数那个就是我们要找的 a a a,因为用下面代码 e x g c d exgcd exgcd算出来的系数只是 ∣ x ∣ + ∣ y ∣ |x|+|y| x+y最小,当然也可以令 y = y , x = x ′ y=y,x=x' y=y,x=x,用扩欧算出来的是后,如果算出来的 x ′ x' x > = 0 >=0 >=0,再调整一下系数把 x ′ x' x变为负数即可。

#include <bits/stdc++.h>
using namespace std;
const int inf = 0x3f3f3f3f;
#define ll long long
ll exgcd(ll a, ll b, ll &x, ll &y) 
    if (!b) 
        x = 1, y = 0;
        return a;
    
    ll d = exgcd(b, a % b, y, x);
    y = y - a / b * x;
    return d;

int main() 
    ll n;
    cin >> n;
    if (n == 1) 
        puts("1");
        return 0;
    
    n *= 2;
    ll res = 1e18;
    for (ll i = 2; i <= n / i; i++) 
        ll a, b;
        if (n % i == 0) 
            a = i, b = n / i;
            if (__gcd(a, b) != 1) continue;
            ll x, y;
            exgcd(a, b, x, y);
            if (x < 0) 
                res 以上是关于ACL Contest 1(补题)的主要内容,如果未能解决你的问题,请参考以下文章

补题日记[2022牛客暑期多校4]A-Task Computing

补题日记[2022牛客暑期多校4]A-Task Computing

SDUT 2021 Spring Individual Contest(for 20) - 1补题

AtCoder Beginner Contest 222(补题)

SDUT 2021 Summer Individual Contest - 2(for 20)(补题)

2019 Multi-University Training Contest 1 (补题)