2019 Multi-University Training Contest 5

Solved Pro.ID Title Ratio(Accepted / Submitted)
1001 fraction 4.17%(7/168)
已补 1002 three arrays 12.69%(76/599) 字典树
1003 geometric problem 1.59%(1/63)
已补 1004 equation 20.65%(310/1501) 思维
已补 1005 permutation 1 24.77%(407/1643) dfs+思维
img 1006 string matching 23.12%(724/3131) exkmp
img 1007 permutation 2 47.19%(688/1458) DP
img 1008 line symmetric 1.87%(11/588) 计算几何
1009 discrete logarithm problem 18.42%(7/38)
1010 find hidden array 6.25%(2/32)

题目

1002

将a序列和b序列存放到两个字典树里面,然后每次贪心的匹配a中的0和b中0,或者a中的1和b中的1,如果没有,那就01或者10。最后获得的数字不一定是当前最小的,不过一定是在C中的,所以只需要在最后排个序就行了。

#include <bits/stdc++.h>
using namespace std;
const int N = 100010;
int son[31*N][2],cnt[62*N],tot,n,x;
vector<int> res;
inline void insert(int head,int x){
    int p = head;
    for(int i=30;i>=0;i--){
        int u = x >> i & 1;
        if(!son[p][u])son[p][u] = ++tot;
        p = son[p][u];
        cnt[p]++;
    }
}
inline int getVal(int p1,int p2){
    int res = 0;
    for(int i=30;i>=0;i--){
        if(son[p1][0] && son[p2][0] && cnt[son[p1][0]] && cnt[son[p2][0]]){
            p1 = son[p1][0];
            p2 = son[p2][0];
            cnt[p1]--;cnt[p2]--;
        }
        else if(son[p1][1] && son[p2][1] && cnt[son[p1][1]] && cnt[son[p2][1]]){
            p1 = son[p1][1];
            p2 = son[p2][1];
            cnt[p1]--;cnt[p2]--;
        }
        else if(son[p1][1] && son[p2][0] && cnt[son[p1][1]] && cnt[son[p2][0]]){
            p1 = son[p1][1];
            p2 = son[p2][0];
            cnt[p1]--;cnt[p2]--;
            res |= (1<<i);
        }
        else if(son[p1][0] && son[p2][1] && cnt[son[p1][0]] && cnt[son[p2][1]]){
            p1 = son[p1][0];
            p2 = son[p2][1];
            cnt[p1]--;cnt[p2]--;
            res |= (1<<i);
        }
    }
    return res;
    
}
int main(){
    int T;scanf("%d",&T);
    while(T--){
        tot = 1;
        res.clear();
        scanf("%d",&n);
        for(int i=1;i<=n;i++){
            scanf("%d",&x);
            insert(0,x);
        }
        for(int i=1;i<=n;i++){
            scanf("%d",&x);
            insert(1,x);
        }
        for(int i=1;i<=n;i++)res.push_back(getVal(0,1));
        sort(res.begin(),res.end());
        for(int i=0;i<n;i++){
            if(i)printf(" ");
            printf("%d",res[i]);
        }
        puts("");
        for(int i=0;i<=tot;i++){
            son[i][0] = son[i][1] = 0;
            cnt[i] = 0;
        }
    }
    return 0;
}

1004

把n个等式按照 \(-b\over a\) 从小到大排序,然后可以发现把n条线\(x={-b\over a}\)画到坐标轴上面可以把x分为n+1个区域,针对每个区域,可以将每个等式的绝对值去掉,然后加到一起变成一个等式,直接解出来看x在不在这个范围即可

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll N = 100010;
ll n;
int t;
ll C;
ll gcd(ll a,ll b){
    return b == 0 ? a : gcd(b,a%b);
}
struct node{
    int a,b;
    bool operator <(const node y){
        return (-b) * y.a < -y.b * a;
    }
}a[N];
ll aa[N],bb[N],tot;
int main(){
    scanf("%d",&t);
    while(t--){
        tot = 0;
        scanf("%lld%lld",&n,&C);
        ll A = 0,B = 0;
        for(ll i=1;i<=n;i++){
            scanf("%lld%lld",&a[i].a,&a[i].b);
            A += a[i].a;
            B += a[i].b;
        }
        sort(a+1,a+n+1);
        ll resa = 0, resb = 0;
        bool flag = false;
        for(ll i=n;i>=0;i--){
            if(A == 0){
                if(B == C){
                    flag = true;
                    break;
                }
                else {
                    continue;
                }
            }
            resa = C-B;
            resb = A;
            if(resb < 0){
                resa = - resa;
                resb = - resb;
            }
            ll g = gcd(resa > 0 ? resa : -resa,resb);
            if(g > 1){
                resa/=g;
                resb/=g;
            }
            if(i >= 1){
                A -= 2 * a[i].a;
                B -= 2 * a[i].b;
            }
            if(i >= 1 && resa * a[i].a < (-a[i].b * resb))continue;
            if(i < n && resa * a[i+1].a >= (-a[i+1].b * resb))continue;
            aa[++tot] = resa;
            bb[tot] = resb;
        }
        if(flag)puts("-1");
        else{
            printf("%lld",tot);
            for(ll i = tot; i>= 1;i--){
                printf(" %lld/%lld",aa[i],bb[i]);
            }
            puts("");
        }
    }
    return 0;
}

1005

企图用组合数学,一直wa找不着北,场后先找到前两个数字然后再dfs还是wa,看题解明白了,但是并不知道自己错在哪里

#include <bits/stdc++.h>
using namespace std;
const int N = 50;
int n,k;
int d[N],u[N];
//d中存在n个数字,他们表示着相对大小,实际大小由整个数组的low和hi决定。
//low表示现在填过的数字中最大的和最小的数字是多少。
int dfs(int x,int low,int hi){
    if(x == n){
        k --;
        if(k == 0){
            for(int i=0;i<n;i++){
                if(i)printf(" ");
                printf("%d",d[i] - low + 1);
            }
            puts("");
            return 1;
        }
        return 0;
    }
    for(int i = hi - n + 1;i <= low + n -1;i++){
        if(u[i])continue;
        u[i] = 1;
        d[x] = i;
        if(dfs(x+1,min(low,i),max(hi,i)) == 1){
            u[i] = 0;
            return 1;
        }
        u[i] = 0;
    }
    return 0;
}
int main(){
    int T;scanf("%d",&T);
    while(T--){
        scanf("%d%d",&n,&k);
        d[0] = n;
        u[n] = 1;
        dfs(1,n,n);
        u[n] = 0;
    }
    return 0;
}

1006

开场SA+LCP获得一T(看SA看晕了),回过头来发现就是个exkmp,直接上板子

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 1e6+10;
char s[N];
int nxt[N];
void pre_EKMP(char x[],int m){
    nxt[0] = m;
    int j = 0;
    while(j+1 < m && x[j] == x[j+1])j++;
    nxt[1] = j;
    int k = 1;
    for(int i=2;i<m;i++){
        int p = nxt[k] + k - 1;
        int l = nxt[i-k];
        if(i + l < p + 1)nxt[i] = l;
        else{
            j = max(0,p-i+1);
            while(i + j < m && x[i+j] == x[j])j++;
            nxt[i] = j;
            k = i;
        }
    }
}
int main(){
    int T;scanf("%d",&T);
    while(T--){
        scanf("%s",s);
        int len = strlen(s);
        pre_EKMP(s,len);
        ll res = 0;
        for(int i=1;i<len;i++){
            if(nxt[i] == len - i){
                res += nxt[i];
            }
            else res += nxt[i] + 1;
        }
        printf("%lld\n",res);
    }
    return 0;
}

1007

学长过的,是我不会的DP

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll mod = 998244353;

ll dp[100005][2];
int main() {
    dp[3][0] = 1LL;
    dp[3][1] = 0LL;
    dp[4][0] = 1LL;
    dp[4][1] = 1LL;
    for(int i = 5; i <= 100000; i++) {
        dp[i][0] = (dp[i - 1][0] + dp[i - 1][1]) % mod;
        dp[i][1] = dp[i - 2][0];
    }

    int T;
    scanf("%d", &T);
    while(T--) {
        int n, x, y;
        scanf("%d%d%d", &n, &x, &y);
        if(x + 1 == y && n > 3) {
            if(y == n || x == 1) puts("1");
            else puts("0");
            continue;
        }
        ll ans = 0;
        int l, r;
        if(x == 1) l = 1;
        else l = x + 1;
        if(y == n) r = n;
        else r = y - 1;
        r -= l - 1;
        //cout << r << endl;
        if(r <= 3) ans = 1LL;
        else ans = (dp[r][0] + dp[r][1]) % mod;

        printf("%lld\n", ans);
    }
    return 0;
}

1008

学长过的,我什么都不会

#include <bits/stdc++.h>

using namespace std;

const double eps = 1e-8;
int cmp(double x) {
    if (fabs(x) < eps) return 0;
    if (x > 0) return 1;
    return -1;
}

const double pi = acos(-1.0);

inline double sqr(double x) {
    return x * x;
}

struct point {
    double x, y;
    point() {}
    point(double a, double b) : x(a), y(b) {}
    void input() {
        scanf("%lf%lf", &x, &y);
    }
    friend point operator + (const point &a, const point &b) {
        return point(a.x + b.x, a.y + b.y);
    }
    friend point operator - (const point &a, const point &b) {
        return point(a.x - b.x, a.y - b.y);
    }
    friend bool operator == (const point &a, const point &b) {
        return cmp(a.x - b.x) == 0 && cmp(a.y - b.y) == 0;
    }
    friend point operator * (const point &a, const double &b) {
        return point(a.x * b, a.y * b);
    }
    friend point operator * (const double &a, const point &b) {
        return point(a * b.x, a * b.y);
    }
    friend point operator / (const point &a, const double &b) {
        return point(a.x / b, a.y / b);
    }
    double norm(){
        return sqrt(sqr(x) + sqr(y));
    }
};

double det(const point &a, const point &b) {
    return a.x * b.y - a.y * b.x;
}

double dot(const point &a, const point &b) {
    return a.x * b.x + a.y * b.y;
}

double dist(const point &a, const point &b) {
    return  (a - b).norm();
}

point rotate_point(const point &p, double A){
    double tx = p.x, ty = p.y;
    return point(tx * cos(A) - ty * sin(A), tx * sin(A) + ty * cos(A));
}

struct line {
    point a, b;
    line() {}
    line(point x, point y) : a(x), b(y) {}
};

line point_make_line(const point a, const point b) {
    return line(a, b);
}

double dis_point_segment(const point p, const point s, const point t) {
    if(cmp(dot(p - s, t - s)) < 0) return (p - s).norm();
    if(cmp(dot(p - t, s - t)) < 0) return (p - t).norm();
    return fabs(det(s - p, t - p) / dist(s, t));
}

void PointProjLine(const point p, const point s, const point t, point &cp){
    double r = dot((t - s), (p - s)) / dot(t - s, t - s);
    cp = s + r * (t - s);
}

bool PointOnSegment(point p, point s, point t){
    return cmp(det(p - s, t - s)) == 0 && cmp(dot(p - s, p - t)) <= 0;
}

bool parallel(line a, line b){
    return !cmp(det(a.a - a.b, b.a - b.b));
}

bool line_make_point(line a, line b, point &res){
    if(parallel(a, b)) return false;
    double s1 = det(a.a - b.a, b.b - b.a);
    double s2 = det(a.b - b.a, b.b - b.a);
    res = (s1 * a.b - s2 * a.a) / (s1 - s2);
    return true;
}

line move_d(line a, const double &len){
    point d = a.b - a.a;
    d = d / d.norm();
    d = rotate_point(d, pi / 2);
    return line(a.a + d * len, a.b + d * len);
}

bool SegmentSamePoints(line i, line j){
    return max(i.a.x, i.b.x) >= min(j.a.x, j.b.x) &&
        max(j.a.x, j.b.x) >= min(i.a.x, i.b.x) &&
        max(i.a.y, i.b.y) >= min(j.a.y, j.b.y) &&
        max(j.a.y, j.b.y) >= min(i.a.y, i.b.y) &&
        cmp(det(j.a - i.a, i.b - i.a) * det(j.b - i.a, i.b - i.a)) <= 0 &&
        cmp(det(i.a - j.a, j.b - j.a) * det(i.b - j.a, j.b - j.a)) <= 0;
}

int T;

int n;
point a[1005];

int main(){
    scanf("%d", &T);
    while(T--){
        scanf("%d", &n);
        for(int i = 0; i < n; i++){
            a[i].input();
        }
        if(n < 5){
            puts("Y");
            continue;
        }

        bool ans = false;

        // 关于某条边的中垂线对称
        for(int i = 0; i < n; i++){
            point fir = a[i];
            point sec = a[(i + 1) % n];
            point mid_p = (fir + sec) / 2;

            point ss1 = sec - fir;
            point mid_q = rotate_point(ss1, pi / 2) * (2500.0) + mid_p;
            point mid_r = rotate_point(ss1, -pi / 2) * (2500.0) + mid_p;
            
            int cnt = 0;
            for(int j = 1; j <= (n + 1) / 2 - 1; j++){
                fir = a[(i + 1 + j) % n];
                sec = a[(i - j + n) % n];

                if(!(fir == sec) && cmp(dis_point_segment(fir, mid_q, mid_r)) == 0 && cmp(dis_point_segment(sec, mid_q, mid_r)) == 0){
                    cnt = 20;
                    break;
                }


                point mid_c = (fir + sec) / 2;
                if(cmp(dis_point_segment(mid_c, mid_q, mid_r)) != 0){
                    cnt++;
                }

                point cp1, cp2;
                PointProjLine(fir, mid_q, mid_r, cp1);
                PointProjLine(sec, mid_q, mid_r, cp2);
                if(!(cp1 == cp2)){
                    cnt++;
                }

                if(n % 2 == 0 && j == (n + 1) / 2 - 1){
                    point ss1 = a[(i + j) % n] - mid_q;
                    point ss2 = a[(i + j + 1) % n] - mid_q;
                    point ss3 = a[(i + j + 2) % n] - mid_q;
                    point ss4 = a[(i + j + 3) % n] - mid_q;

                    point ss5 = mid_r - mid_q;

                    int bb1 = cmp(det(ss5, ss2));
                    int bb2 = cmp(det(ss5, ss1));
                    int bb3 = cmp(det(ss5, ss3));
                    int bb4 = cmp(det(ss5, ss4));

                    int bb5 = bb1 * bb2;
                    int bb6 = bb4 * bb3;

                    if(bb5 > 0 || bb6 > 0){
                        ;
                    }
                    else{
                        cnt += 20;
                    }
                }

                if(cnt > 1){
                    break;
                }
            }

            if(cnt <= 1){
                ans = true;
                break;
            }
        }

        if(ans){
            puts("Y");
            continue;
        }

        // 偶数点时:关于对边连线对称
        if(n % 2 == 0){
            for(int i = 0; i < n / 2; i++){
                point fir = a[i];
                point sec = a[i + n / 2];

                point ss1 = sec - fir;
                point mid_q = ss1 * 2500.0 + fir;
                point mid_r = ss1 * (-2500.0) + fir;

                int cnt = 0;
                for(int j = 1; j < n / 2; j++){
                    fir = a[(i + j) % n];
                    sec = a[(i - j + n) % n];

                    if(!(fir == sec) && cmp(dis_point_segment(fir, mid_q, mid_r)) == 0 && cmp(dis_point_segment(sec, mid_q, mid_r)) == 0){
                        cnt = 20;
                        break;
                    }

                    point mid_c = (fir + sec) / 2;
                    if(cmp(dis_point_segment(mid_c, mid_q, mid_r)) != 0){
                        cnt++;
                        continue;
                    }

                    point cp1, cp2;
                    PointProjLine(fir, mid_q, mid_r, cp1);
                    PointProjLine(sec, mid_q, mid_r, cp2);
                    if(!(cp1 == cp2)){
                        cnt++;
                    }

                    if(cnt > 1){
                        break;
                    }
                }

                if(cnt <= 1){
                    ans = true;
                    break;
                }
            }
            if(ans){
                puts("Y");
                continue;
            }
        }
        // 奇数点时:检查能不能调整正对的两个点。
        else{
            for(int i = 0; i < n; i++){
                point fir = a[(i + 1) % n];
                point sec = a[(i - 1 + n) % n];

                point mid_p = (fir + sec) / 2;

                point ss1 = mid_p - a[i];
                point mid_q = ss1 * 2500.0 + a[i];
                point mid_r = ss1 * (-2500.0) + a[i];

                int cnt = 0;
                for(int j = 1; j <= n / 2; j++){
                    // printf("%d\n", j);
                    fir = a[(i + j) % n];
                    sec = a[(i - j + n) % n];

                if(!(fir == sec) && cmp(dis_point_segment(fir, mid_q, mid_r)) == 0 && cmp(dis_point_segment(sec, mid_q, mid_r)) == 0){
                    cnt = 20;
                    break;
                }

                    point mid_c = (fir + sec) / 2;
                    if(cmp(dis_point_segment(mid_c, mid_q, mid_r)) != 0){
                        // printf("%d: mid wrong\n", j);
                        cnt++;
                    }

                    point cp1, cp2;
                    PointProjLine(fir, mid_q, mid_r, cp1);
                    PointProjLine(sec, mid_q, mid_r, cp2);
                    if(!(cp1 == cp2)){
                        // printf("%d: cp wrong\n", j);
                        cnt++;
                    }

                    point ss1 = a[(i + j - 1 + n) % n] - mid_q;
                    point ss2 = a[(i + j) % n] - mid_q;
                    point ss3 = a[(i + j + 1) % n] - mid_q;
                    point ss4 = a[(i + j + 2) % n] - mid_q;

                    point ss5 = mid_r - mid_q;

                    int bb1 = cmp(det(ss5, ss2));
                    int bb2 = cmp(det(ss5, ss1));
                    int bb3 = cmp(det(ss5, ss3));
                    int bb4 = cmp(det(ss5, ss4));

                    int bb5 = bb1 * bb2;
                    int bb6 = bb4 * bb3;

                    if(bb5 > 0 || bb6 > 0){
                        ;
                    }
                    else{
                        cnt += 20;
                    }

                    if(cnt > 1){
                        break;
                    }
                }

                if(cnt <= 1){
                    // printf("%d\n", i);
                    ans = true;
                    break;
                }
            }
            if(ans){
                puts("Y");
                continue;
            }
        }

        // 偶数时:还要检查是不是正对面的点是偏的
        if(n % 2 == 0){
            for(int i = 0; i < n; i++){
                point fir = a[(i + 1) % n];
                point sec = a[(i - 1 + n) % n];

                point mid_p = (fir + sec) / 2;

                point ss1 = mid_p - a[i];
                point mid_q = ss1 * 2500.0 + a[i];
                point mid_r = ss1 * (-2500.0) + a[i];

                int cnt = 0;
                for(int j = 1; j <= n / 2; j++){
                    fir = a[(i + j) % n];
                    sec = a[(i - j + n) % n];

                    if(!(fir == sec) && cmp(dis_point_segment(fir, mid_q, mid_r)) == 0 && cmp(dis_point_segment(sec, mid_q, mid_r)) == 0){
                        cnt = 20;
                        break;
                    }

                    point mid_c = (fir + sec) / 2;
                    if(cmp(dis_point_segment(mid_c, mid_q, mid_r)) != 0){
                        cnt++;
                        continue;
                    }

                    point cp1, cp2;
                    PointProjLine(fir, mid_q, mid_r, cp1);
                    PointProjLine(sec, mid_q, mid_r, cp2);
                    if(!(cp1 == cp2)){
                        cnt++;
                    }

                    if(cnt > 1){
                        break;
                    }
                }

                if(cnt <= 1){
                    ans = true;
                    break;
                }
            }
            if(ans){
                puts("Y");
                continue;
            }
        }

        if(ans){
            puts("Y");
        }
        else{
            puts("N");
        }
    }
    return 0;
}
posted @ 2019-08-05 21:32  kpole  阅读(240)  评论(0编辑  收藏  举报