1. 程式人生 > >2017 ACM/ICPC Asia Regional Qingdao Online【solved:7 / 11】

2017 ACM/ICPC Asia Regional Qingdao Online【solved:7 / 11】

hdu 6206 Apple(計算幾何+java高精度)

題意:給你三個點,保證不再同一條直線上,再給你一點,問你是否在這三個點形成的圓外。

思路:用java套個板子即可。就是求出三個點外接圓的圓心和半徑判斷下。

import java.math.BigInteger;
import java.math.BigDecimal;
import java.util.Scanner;

public class Main {
    public static void main(String args[]) {
        Scanner in = new Scanner(System.in
); int t = in.nextInt(); while (t > 0) { t--; long x1,y1,x2,y2,x3,y3,x,y; x1 = in.nextLong(); y1 = in.nextLong(); x2 = in.nextLong(); y2 = in.nextLong(); x3 = in.nextLong(); y3 = in.nextLong
(); x = in.nextLong(); y = in.nextLong(); BigDecimal X1 = new BigDecimal(x1); BigDecimal Y1 = new BigDecimal(y1); BigDecimal X2 = new BigDecimal(x2); BigDecimal Y2 = new BigDecimal(y2); BigDecimal X3 = new BigDecimal(x3);
BigDecimal Y3 = new BigDecimal(y3); BigDecimal X = new BigDecimal(x); BigDecimal Y = new BigDecimal(y); BigDecimal a1 = X2.subtract(X1); BigDecimal b1 = Y2.subtract(Y1); BigDecimal two = new BigDecimal(2); BigDecimal c1 = (a1.multiply(a1).add(b1.multiply(b1))).divide(two); BigDecimal a2 = X3.subtract(X1); BigDecimal b2 = Y3.subtract(Y1); BigDecimal c2 = (a2.multiply(a2).add(b2.multiply(b2))).divide(two); BigDecimal d = a1.multiply(b2).subtract(a2.multiply(b1)); BigDecimal cpx = X1.add((c1.multiply(b2).subtract(c2.multiply(b1))).divide(d)); BigDecimal cpy = Y1.add((a1.multiply(c2).subtract(a2.multiply(c1))).divide(d)); //System.out.println(cpx.doubleValue()); //System.out.println(cpy.doubleValue()); BigDecimal r = X1.subtract(cpx).multiply(X1.subtract(cpx)).add(Y1.subtract(cpy).multiply(Y1.subtract(cpy))); BigDecimal dist = X.subtract(cpx).multiply(X.subtract(cpx)).add(Y.subtract(cpy).multiply(Y.subtract(cpy))); if (dist.compareTo(r) == 1) { System.out.println("Accepted"); }else { System.out.println("Rejected"); } } } }

hdu 6208 The Intersection(AC自動機)

題意:給你n個字串,問你其中是否存在某個串,滿足所有的串的都是它的子串。

思路:AC自動機水題。注意卡IO。

#include <bits/stdc++.h>
using namespace std;
const int maxn = 1e5 + 5;

struct AC
{
    int nxt[maxn][30],FAIL[maxn],edd[maxn],root,L;//nxt記錄節點,在這裡edd指標代表以當前節點為字串尾的字串個數
    int mark[maxn];
    int newnode()
    {
        for(int i=0; i<26; i++)
            nxt[L][i]=-1;//節點連線的邊初始化為-1
        edd[L]=0;
        mark[L]=0;
        return L++;
    }
    void init()
    {
        L=0;
        root=newnode();
    }

    void insert(char buf[])//trie樹的建立
    {
        int now=root;
        int l = strlen(buf);
        for(int i=0; i<l; i++)
        {
            if(nxt[now][buf[i]-'a']==-1)nxt[now][buf[i]-'a']=newnode();
            now=nxt[now][buf[i]-'a'];
        }
        edd[now]++;
    }
    void build()//建立ac自動機
    {
        queue<int>que;
        for(int i=0; i<26; i++)
        {
            if(nxt[root][i]==-1)nxt[root][i]=root;
            else                                 //若有連邊則將節點加入佇列 ,並將FAIL指標指向root
            {
                FAIL[nxt[root][i]]=root;
                que.push(nxt[root][i]);
            }
        }
        while(!que.empty())
        {
            int now=que.front();
            que.pop();
            for(int i=0; i<26; i++)
            {
                if(nxt[now][i]==-1)            //若無連邊,則將該邊指向當前節點FAIL指標指向的相應字元連線的節點
                    nxt[now][i]=nxt[FAIL[now]][i];
                else                            //若有連邊,則將兒子節點的FAIL指標指向當前節點FAIL指標指向相應字元接的節點
                {
                    FAIL[nxt[now][i]]=nxt[FAIL[now]][i];
                    que.push(nxt[now][i]); //加入佇列繼續遍歷
                }
            }
        }
    }
    int query(char buf[])
    {
        int now=root;
        int res=0;
        int l = strlen(buf);
        for(int i=0; i<l; i++)
        {
            now=nxt[now][buf[i]-'a'];
            int temp=now;
            while(temp!=root&&mark[temp]==0)//根據題目要求改變形式
            {
                res+=edd[temp];
                edd[temp]=0;
                mark[temp]=1;
                temp=FAIL[temp];
            }
        }
        return res; //在這裡返回的是匹配到的模式串的數量
    }
}ac;
char s[maxn], longest[maxn];
int main()
{
    int T;
    scanf("%d", &T);
    while(T--)
    {
        int n;
        scanf("%d", &n);
        ac.init();
        getchar();
        int maxLen = 0;
        for(int i = 0; i < n; i++)
        {
            gets(s);
            int len = strlen(s);
            if(len > maxLen)
            {
                maxLen = len;
                strcpy(longest, s);
            }
            ac.insert(s);
        }
        ac.build();
        int sum = ac.query(longest);
        if(sum == n)    puts(longest);
        else puts("No");

    }
    return 0;
}

hdu 6209 The Intersection(整數化小數)

題意:等價於讓你用分子分母均不大於100000的分數形式,去精確表示一個小數。

思路:stern brocot tree。知道這個就很簡單了,在樹上二分找即可。這題卡long double。

#include <bits/stdc++.h>
using namespace std;
int ansl, ansr;
void solve(int l1, int r1, int l2, int r2, long double decimal)
{
    if (l1 == l2 && r1 == r2) return;
    if (fabs((long double)1.0 * l1 / r1 - decimal) < fabs((long double)1.0 * ansl / ansr - decimal)) ansl = l1, ansr = r1;
    if (fabs((long double)1.0 * l2 / r2 - decimal) < fabs((long double)1.0 * ansl / ansr - decimal)) ansl = l2, ansr = r2;

    int ml = (l1 + l2);
    int mr = (r1 + r2);
    if (mr > 100000) return;
    if ((long double)1.0 * ml / mr >= decimal) solve(l1, r1, ml, mr, decimal);
    else solve(ml, mr, l2, r2, decimal);
}
void gao(int k)
{
    for(int i = 1; i <= 50; i++)
    {
        if(i * i * i == k)
        {
            printf("%d/1\n", i * i);
            return ;
        }
    }
    long double temp = pow((long double)k, (long double)2.0 / 3);
    int lb = floorl(temp);//floor函式:向下舍入
    long double rb = temp - lb;
    ansl = 0, ansr = 1;
    solve(0, 1, 1, 1, rb);
    printf("%d/%d\n", lb * ansr + ansl, ansr);
}
int main()
{
    int T, k;
    scanf("%d", &T);
    while(T--)
    {
        scanf("%d", &k);
        gao(k);
    }
    return 0;
}

hdu 6213 Chinese Zodiac(water)

#include <bits/stdc++.h>
using namespace std;
string s[] = {"rat", "ox", "tiger", "rabbit", "dragon", "snake", "horse", "sheep", "monkey", "rooster", "dog" ,"pig"};

int main()
{
    int T;
    scanf("%d", &T);
    map<string, int>ma;
    for(int i= 0; i <12; i++)
        ma[s[i]] = i;
    while(T--)
    {
        string a, b;
        cin >> a >>b;
        int x = ma[a], y = ma[b];
        int ans = y - x;
        if(ans <= 0)    ans += 12;
        printf("%d\n", ans);
    }
    return 0;
}

hdu 1009 Smallest Minimum Cut (最小割的最小邊集)

題意:給一個圖,求一個最小割的最小邊集的大小。

思路:邊權擴大一個相對較大的係數倍,然後最大流/係數就是最大流,最大流%係數就是最小割的最小邊集。

#include <bits/stdc++.h>
using namespace std;
const int maxv = 200 + 5;
struct Dinic
{
    int vs, es;
    struct edge{int to, cap, rev;};
    vector<edge>G[maxv];
    int level[maxv];//頂點到源點的距離標號
    int iter[maxv];//當前弧,在其之前的邊已經沒有用了
//    void init()
//    {
//}
    void addedge(int from, int to, int cap)
    {
        G[from].push_back({to, cap, (int)G[to].size()});
        G[to].push_back({from, 0, (int)G[from].size() - 1});
    }

    void bfs(int s)
    {
        memset(level, -1, sizeof(level));
        queue<int>que;
        level[s] = 0;
        que.push(s);
        while(que.size())
        {
            int v = que.front();que.pop();
            for(auto &e : G[v])
            {
                if(e.cap > 0 && level[e.to] == -1)
                {
                    level[e.to] = level[v] + 1;
                    que.push(e.to);
                }
            }
        }
    }
    //dfs找增廣路
    int dfs(int v, int t, int f)
    {
        if(v == t)  return f;
        for(int &i = iter[v]; i < G[v].size(); i++)
        {
            edge &e = G[v][i];
            if(e.cap > 0 && level[v] < level[e.to])
            {
                int d = dfs(e.to, t, min(f, e.cap));
                if(d > 0)
                {
                    e.cap -= d;
                    G[e.to][e.rev].cap += d;
                    return d;
                }
            }
        }
        return 0;
    }

    int max_flow(int s, int t)
    {
        int flow = 0;
        for(;;)
        {
            bfs(s);
            if(level[t] == -1)  return flow;
            memset(iter, 0, sizeof(iter));
            int f;
            while((f = dfs(s, t, 0x3f3f3f3f)) > 0)
            {
                flow += f;
            }
        }
    }
};

int main()
{
    int T, vs, es, s, t;
    scanf("%d", &T);
    while(T--)
    {
        scanf("%d%d%d%d", &vs, &es, &s, &t);
        Dinic dinic;
        dinic.vs = vs, dinic.es = es;
        for(int i = 0, u, v, w; i < es; i++)
        {
            scanf("%d%d%d", &u, &v, &w);
            dinic.addedge(u, v, w * (vs + 1)+ 1);
        }
        printf("%d\n", dinic.max_flow(s, t) % (vs + 1));
    }
    return 0;
}

hdu 6215 Brute Force Sorting(思維?)

題意:給一個長度為n的序列,重複以下操作,刪除不合法的數字,直到全部符合為止。注意:比如第一輪時,如果a[4]被刪除了,a[5]仍然要和a[4]和a[6]比較。同一輪內的刪除操作是同時刪除的。
A number A[i] of the array is sorted if it satisfies the following requirements.
1. A[i] is the first element of the array, or it is no smaller than the left one A[i−1].
2. A[i] is the last element of the array, or it is no bigger than the right one A[i+1].

思路:找出每一個單調非減的區間,然後考慮每一個數字只會被最多兩個區間選擇作為刪除物件,所以是O(n)。所以對相鄰區間進行模擬題意即可,用一個vector維護區間。

#include <bits/stdc++.h>
using namespace std;
const int maxn = 1e5 + 5;
const int INF = 0x3f3f3f3f;
int main()
{
    int T, n;
    scanf("%d", &T);
    while(T--)
    {
        scanf("%d", &n);
        vector<int>a, ans;
        a.resize(n + 5);
        for(int i = 1; i <= n; i++)   scanf("%d", &a[i]);
        a[n + 1] = 0x3f3f3f3f;
        vector<pair<int, int>>vec;
        int last = -1, lb;
        for(int i = 1; i <= n; i++)
        {
            if(last == -1)  last = lb = i;
            else if(a[last] <= a[i] && a[i] <= a[i + 1])    last = i;
            else
            {
                vec.push_back({lb, last});
                vec.push_back({i, i});
                last = -1;
            }
        }
        if(last != -1)  vec.push_back({lb, last});

        int update = 1;
        while(update && vec.size())
        {
            update = 0;
            vector<pair<int, int>>temp;
            int INF = 0x3f3f3f3f;
            vector<pair<int, int>>veccc;
            veccc = vec;
            for(int i = 0; i < vec.size() - 1; i++)
            {
                int lb1 = vec[i].first;
                int rb1 = vec[i].second;
                int lb2 = vec[i + 1].first;
                int rb2 = vec[i + 1].second;
                if(a[rb1] > a[lb2]) rb1--, lb2++, update = 1;
                veccc[i].second = min(veccc[i].second, rb1);
                veccc[i+1].first = max(veccc[i + 1].first, lb2);
            }

            vec.clear();
            for(auto o : veccc)
            {
                if(o.first > o.second)  continue;
                vec.push_back(o);
            }
            a = ans;
        }
        for(auto o: vec)
        {
            for(int i = o.first; i <= o.second; i++)
            {
                ans.push_back(a[i]);
            }
        }
        printf("%d\n", ans.size());
        for(int i= 0; i < ans.size(); i++)
            printf("%d ", ans[i]);
        puts("");
    }
    return 0;
}

hdu 6216 A Cubic number and A Cubic Number(water)

題意:給出一個質數p(p1e12),問你它是否為兩個完全立方數的差。

思路:即p為質數時,x3y3=(xy)×(x2+x×y+y)=p。有無x,y正整數解。顯然由於p是質數,所以x-y=1。所以轉換成一個關於y的一元二次方程。求解驗證即可。

#include <bits/stdc++.h>
using namespace std;
long long Zcsqrt(long long p)
{
    long long temp = sqrt(p);
    temp = max(0LL, temp - 5);
    while((temp + 1) * (temp + 1) <= p) temp++;
    return temp;
}
bool solve(long long p)
{
    long long delta = 12LL * p - 3;
    if(delta <= 0)   return false;
    long long sqrtDelta = Zcsqrt(delta);
    if(sqrtDelta * sqrtDelta != delta)  return false;
    sqrtDelta -= 3;
    if(sqrtDelta % 6 != 0)  return false;
    return true;
}
int main()
{
    int T;
    scanf("%d", &T);
    while(T--)
    {
        long long p;
        scanf("%lld", &p);
        if(solve(p))    puts("YES");
        else puts("NO");
    }
    return 0;
}