Problem solving report of GRYZ20211029 Simulation Competition

catalogue

Expected score: \ (100+40+20 = 160pts \)
Actual score: \ (100+40+0=140pts \)

I don't know why I'm so delicious.

T1 T2 T3
T207974 function T207975 generals T207976 toy

T1 generals

CF732D original question.

First of all, you consider a greedy. The later you attack a person, the easier it is to defeat him. Because the later you get, the more troops you accumulate.

So you can judge whether there is a solution by judging whether you can beat everyone in the latest exposed round.

Unfortunately, the question asks us how many rounds we can kill everyone else as soon as possible.

Obviously, the above is the worst case. Obviously, a better case is to kill the last person in an earlier round.

Then you find that you can use vector and set to maintain the process of finding a better situation.

Then you consider quickly judging whether a situation has a solution. You find that if the value of the non attack round is regarded as \ (1 \) and the value of the attack round is regarded as \ (a_{d_i} \), then if the minimum prefix and \ (\ ge 0 \) of the whole sequence have a solution, otherwise there is no solution. This information can be maintained using the segment tree.

Then it's done.

The time complexity is \ (\ mathcal O(n \log n) \), because the best case will only be searched \ (n \) times at most, and all operations in it are single \ (\ log \). Because there are a lot of operations, the constant may be large.

Then I got stuck in the evaluation machine, but I didn't get stuck in CF.

Introduce the positive solution:

Through the above description, we have check ed whether a certain scheme has a solution through \ (O(n) \), and can get the worst-case scheme through greed.

Then you can do it by directly dividing the answer by two.

#include<iostream>
#include<cstdio>
#include<vector>
#include<set>
#define orz cout<<"lkp AK IOI!\n"
using namespace std;
const int MAXN = 2e5 + 10;
const int INF = 1e9 + 7;
const int mod = 1e9 + 7;

struct node {
    int pos, id, rk;
    bool operator < (const node &b) const { 
        if(pos == b.pos) {
            if(id == b.id) return rk > b.rk;
            return id < b.id;
        }
        return pos > b.pos; 
    }
};

int n, m, ans = 0;
int d[MAXN], a[MAXN], b[MAXN];
int lst[MAXN];
vector<int> pos[MAXN]; 
set<node> S;

int read(){
    int s = 0, f = 0;
    char ch = getchar();
    while(!isdigit(ch))  f |= (ch == '-'), ch = getchar();
    while(isdigit(ch)) s = (s << 1) + (s << 3) + ch - '0' , ch = getchar();
    return f ? -s : s;
}
namespace Seg {
    #define lson i << 1
    #define rson i << 1 | 1
    int Min[MAXN << 2], sum[MAXN << 2];
    void Push_up(int i) {
        sum[i] = sum[lson] + sum[rson];
        Min[i] = min(Min[lson], sum[lson] + Min[rson]);
    }
    void Build(int i, int l, int r) {
        if(l == r) {
            Min[i] = sum[i] = b[l];
            return ;
        }
        int mid = (l + r) >> 1;
        Build(lson, l, mid), Build(rson, mid + 1, r);
        Push_up(i);
    }
    void Modify(int i, int l, int r, int pos, int val) {
        if(l == r) {
            Min[i] = sum[i] = val;
            return ;
        }
        int mid = (l + r) >> 1;
        if(mid >= pos) Modify(lson, l, mid, pos, val);
        else Modify(rson, mid + 1, r, pos, val);
        Push_up(i);
    }
}

int main() {
//	freopen("generals.in","r",stdin);
//	freopen("generals.out","w",stdout);
    n = read(), m = read();
    for(int i = 1; i <= n; ++i) {
        d[i] = read();
        if(!d[i]) continue;
        pos[d[i]].push_back(i);
        lst[d[i]] = i;
    }
    for(int i = 1; i <= m; ++i) a[i] = read();
    for(int i = 1; i <= n; ++i) {
        if(lst[d[i]] == i) {
            b[i] = - a[d[i]];
            int M = pos[d[i]].size();
            S.insert((node){i, d[i], M - 1});
        } else {
            b[i] = 1;
        }
    }
//    for(int i = 1; i <= n; ++i) cout<<b[i]<<" "; puts("\n");
    Seg::Build(1, 1, n);
    if(Seg::Min[1] >= 0) {
        ans = S.begin()->pos;
    } else {
        puts("-1");
        return 0;
    }
    set<node>::iterator it;
    while(true) {
        it = S.begin();
        node x = *it;
        S.erase(it);
        if(x.rk == 0) {
            ans = x.pos;
            break;
        } else {
            Seg::Modify(1, 1, n, x.pos, 1);
            x.rk --;
            x.pos = pos[x.id][x.rk];
            Seg::Modify(1, 1, n, x.pos, - a[x.id]);
            int res = Seg::Min[1];
            if(res < 0) break;
            else {
                S.insert(x);
                ans = S.begin()->pos;
            }
        }
    }
    printf("%d\n", ans);
//	fclose(stdin);
//	fclose(stdout);
	return 0;
}
/*
10 3
0 0 1 2 3 0 2 0 1 2
1 1 4
*/

T2 function

For the first 40pts, pretreat the wire screen and ask \ (f(x) \).

Positive solution:

Suppose there is a prime factor of \ (2 \) at the beginning. If you consider prime numbers \ (p_i \) other than \ (2 \), they are all odd numbers first. If you take \ (\ varphi (p_i) \) once, it will become \ (p_i - 1 \), and you can find that this \ (p_i - 1 \) can be disassembled into $2 \times $and some other prime factors. The number of times of \ (2 \) must be \ (+ 1 \), and each time taking \ (\ varphi \) will only make the number of times of \ (2 \) \ (- 1 \), so when \ (2 \) appears, when there are other prime numbers, the number of times of \ (2 \) will not be reduced. In other words, after \ (2 \) appears, it will always exist. So the answer is the number of factors that generate \ (2 \) in the whole process.

If there is no \ (2 \) at the beginning, it will appear \ (2 \) the second time. You only need to do one more operation than the above answer.

If \ (\ sqrt n \) decomposes the prime factor, the complexity is \ (\ mathcal O(n \sqrt n) \).

If the minimum prime factor of each number is screened, it can be \ (\ mathcal O(n \log n) \).

How many \ (2 \) can be generated if each data is continuously fetched \ (\ varphi \) in preprocessing? \ (\ mathcal O(n) \).

/*
Work by: Suzt_ilymtics
Problem: I don't know the name
Knowledge: Garbage algorithm
Time: O((yes)
*/
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<queue>
#define int long long
#define orz cout<<"lkp AK IOI!"<<endl

using namespace std;
const int MAXN = 1e6+5;
const int INF = 1e9+7;
const int mod = 1e9+7;

int T, n;
int p[MAXN], q[MAXN];
int cnt[MAXN];

int read(){
    int s = 0, f = 0;
    char ch = getchar();
    while(!isdigit(ch))  f |= (ch == '-'), ch = getchar();
    while(isdigit(ch)) s = (s << 1) + (s << 3) + ch - '0' , ch = getchar();
    return f ? -s : s;
}

int prim[MAXN], vis[MAXN], Cnt = 0;
void Init() {
    int M = 1000000;
    for(int i = 2; i <= M; ++i) {
        if(!vis[i]) prim[++Cnt] = i, vis[i] = i;
        for(int j = 1; j <= Cnt && i * prim[j] <= M; ++j) {
            vis[i * prim[j]] = prim[j];
            if(i % prim[j] == 0) break;
        }
    }
}

void Work(int x, int k) {
    x--;
    while(x != 1) {
        cnt[vis[x]] += k;
        x /= vis[x];
    }
}

signed main()
{
    Init();
	T = read();
	while(T--) {
	    memset(cnt, false, sizeof cnt);
	    n = read();
	    int M = 0; bool flag = true;
	    for(int i = 1; i <= n; ++i) {
	        p[i] = read(), q[i] = read();
	        cnt[p[i]] += q[i];
	        if(p[i] == 2) flag = false;
	        M = max(p[i], M);
        }
        for(int i = M; i >= 3; --i) {
            if(!cnt[i]) continue;
            Work(i, cnt[i]);
        }
        printf("%lld\n", cnt[2] + flag);
    }
    return 0;
}

T3 toy

CF618E original question

Each line segment is regarded as a complex number, and then transformed into the triangular form of the complex number.

Elongation can be transformed into expansion \ (k \) times, where \ (k \) is the ratio of the length after elongation to the original length.

Rotation can be solved by using the relevant knowledge of high school mathematics.

\[\mid r_1 \mid (\cos \alpha + i \sin \alpha) \times \mid r_2 \mid (\cos \beta + i \sin \beta) = \mid r_1 \mid \mid r_2 \mid (\cos (\alpha + \beta) + i \sin (\alpha + \beta)) \]

Overloading a complex number is a line segment tree board.

In addition, the radian system is used in C + +. The formula of angle system to radian system is \ (\ frac{n \pi}{180} \), \ (\ pi \) needs to be defined by itself. math.h has the value of \ (\ pi \), which is about 20 bits. It should be enough.

Again, std uses a matrix, which is trampled by this algorithm.

/*
Work by: Suzt_ilymtics
Problem: I don't know the name
Knowledge: Garbage algorithm
Time: O((yes)
*/
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<queue>
#define LL long long
#define orz cout<<"lkp AK IOI!"<<endl

using namespace std;
const int MAXN = 3e5+5;
const int INF = 1e9+7;
const int mod = 1e9+7;
const double pi = 3.14159265358979323846;

struct Complex { // complex 
    double x, y;
    Complex() { x = y = 0.0; }
    Complex(double a, double b) { x = a, y = b; }
    Complex(double angle) { x = cos(angle), y = sin(angle); }
    Complex operator + (Complex b) { return Complex(this->x + b.x, this->y + b.y); }
    Complex operator * (Complex b) { return Complex(this->x * b.x - this->y * b.y, this->y * b.x + this->x * b.y); }
    double Calc() { return sqrt(x * x + y * y); }
};

int n, m;

int read(){
    int s = 0, f = 0;
    char ch = getchar();
    while(!isdigit(ch))  f |= (ch == '-'), ch = getchar();
    while(isdigit(ch)) s = (s << 1) + (s << 3) + ch - '0' , ch = getchar();
    return f ? -s : s;
}

namespace Seg {
    #define lson i << 1
    #define rson i << 1 | 1
    Complex sum[MAXN << 2], lazy[MAXN << 2];
    void Push_up(int i) { sum[i] = sum[lson] + sum[rson]; }
    void Build(int i, int l, int r) {
        lazy[i].x = 1.0, lazy[i].y = 0.0;
        if(l == r) {
            sum[i].x = 1.0, sum[i].y = 0.0;
            return ;
        }
        int mid = (l + r) >> 1;
        Build(lson, l, mid), Build(rson, mid + 1, r);
        Push_up(i);
    }
    void Push_down(int i) {
        lazy[lson] = lazy[lson] * lazy[i], lazy[rson] = lazy[rson] * lazy[i];
        sum[lson] = sum[lson] * lazy[i], sum[rson] = sum[rson] * lazy[i];
        lazy[i].x = 1.0, lazy[i].y = 0.0;
    }
    void Modify(int i, int l, int r, int L, int R, Complex v) {
        if(L <= l && r <= R) {
            sum[i] = sum[i] * v, lazy[i] = lazy[i] * v;
            return ;
        }
        Push_down(i);
        int mid = (l + r) >> 1;
        if(mid >= L) Modify(lson, l, mid, L, R, v);
        if(mid < R) Modify(rson, mid + 1, r, L, R, v);
        Push_up(i);
    }
    Complex Query(int i, int l, int r, int pos) {
        if(l == r) return sum[i];
        Push_down(i);
        int mid = (l + r) >> 1; Complex ans;
        if(mid >= pos) return Query(lson, l, mid, pos);
        else return Query(rson, mid + 1, r, pos);
    }
}

int main()
{
	n = read(), m = read();
	Seg::Build(1, 1, n);
	for(int i = 1, x, y; i <= m; ++i) {
	    double z;
	    scanf("%d%d%lf", &x, &y, &z);
	    if(x == 1) {
	        Complex res = Seg::Query(1, 1, n, y);
	        Seg::Modify(1, 1, n, y, y, Complex(1.0 + 1.0 * z / res.Calc(), 0));
        } else {
            Seg::Modify(1, 1, n, y, n, Complex(1.0 * pi * (-z) / 180.0));
        }
        printf("%.10lf %.10lf\n", Seg::sum[1].x, Seg::sum[1].y);
    }
    return 0;
}

Posted on Fri, 29 Oct 2021 22:21:49 -0400 by bluns