2017 ACM/ICPC Asia Regional Qingdao Online

2017 ACM/ICPC Asia Regional Qingdao Online

5題。。。還好吧。。。不過有個300人做出來的我們沒做出來,稍微有點遺憾。按過題順序:

上來我開了01,發現是個水題,抄了一發板子,WA。。發現有100+人提交,沒人通過。。。感覺自己naive,就暫時放到一邊。學弟開了08,發現水題,寫了一發,WA,改了改過了。。

1008 Chinese Zodiac

#include<iostream>
#include<cstdio>
#include<ctime>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<map>
using namespace std;
typedef long long LL;
int T;
map<string,int>a;
int main()
{//freopen("input.txt","r",stdin);
 //freopen("input.txt","w",stdout);
 a["rat"]=0;
 a["ox"]=1;
  a["tiger"]=2;
  a["rabbit"]=3;
  a["dragon"]=4;
  a["snake"]=5;
  a["horse"]=6;
  a["sheep"]=7;
  a["monkey"]=8;
  a["rooster"]=9;
  a["dog"]=10;
   a["pig"]=11;
 scanf("%d",&T);
 while(T--)
 {int x,y;
  string s;
  cin>>s;
  x=a[s];
  cin>>s;
  y=a[s];
  x=(y-x+12)%12;
  if(x==0)x=12;
  printf("%d\n",x);
 }
 return 0;
}

這時候老譚在搞1011,數學題,我在看1009網絡流。

老譚的1011 A Cubic number and A Cubic Number

#include<iostream>
#include<cstdio>
typedef long long LL;

using namespace std;
const LL maxn=1e18;

LL tr[1000005];

inline LL mypow(LL n){
    return n*n*n;
}

int main()
{
    int    cnt=0;
    for(LL i=2;i<=1000000;i++)
        tr[++cnt]=LL(mypow(i)-mypow(i-1));

    //cout<<tr[cnt]<<endl;
    int T;
    cin>>T;
    while(T--){
        LL  x;
        int i;
        cin>>x;
        for(i=1;i<=cnt;i++)
            if(tr[i]==x){
                cout<<"YES"<<endl;
                break;
            }
            else if(tr[i]>x){
                cout<<"NO"<<endl;
                break;
            }
        if(i>cnt)cout<<"NO"<<endl;
    }
    return 0;
}

我的1009,這個要求達到最大流的最小的割邊集大小。因爲被割的邊一定是滿流邊,所以跑完最大流後把滿流邊的容量置1,非滿流邊置爲無窮,跑新的最大流,就是割邊集size,好像見過這題??naive的T了兩發(dinic的鍋?)後改成sap過了。

這題其實還有辦法。因爲每條邊的容量最大255,所以可以把每條邊的容量f設爲他原本容量的E(邊數)倍加1,即(E+1)*f+1,這樣最後求出的流量除以(E+1)就是實際流量,模(E+1)就是邊集大小。

1009 Smallest Minimum Cut

#include<bits\stdc++.h>
using namespace std;

const int MAXN=307;
const int MAXM=10007;
const int oo=0x3f3f3f3f;

struct Node
{
    int from, to, next;
    int cap;
}edge[MAXM];
int tol;
int head[MAXN];
int dep[MAXN];
int gap[MAXN];//gap[x]=y :說明殘留網絡中dep[i]==x的個數爲y
struct SAP
{
    int n;//n是總的點的個數,包括源點和匯點

    void init(int _n)
    {
        n=_n;
        tol=0;
        memset(head, -1, sizeof(head));
    }

    void addedge(int u, int v, int w)
    {
        edge[tol].from=u;
        edge[tol].to=v;
        edge[tol].cap=w;
        edge[tol].next=head[u];
        head[u]=tol++;
        edge[tol].from=v;
        edge[tol].to=u;
        edge[tol].cap=0;
        edge[tol].next=head[v];
        head[v]=tol++;
    }
    void BFS(int start, int end)
    {
        memset(dep, -1, sizeof(dep));
        memset(gap, 0, sizeof(gap));
        gap[0]=1;
        int que[MAXN];
        int front, rear;
        front=rear=0;
        dep[end]=0;
        que[rear++]=end;
        while(front!=rear)
        {
            int u=que[front++];
            if(front==MAXN)front=0;
            for(int i=head[u];i!=-1;i=edge[i].next)
            {
                int v=edge[i].to;
                if(dep[v]!=-1)continue;
                que[rear++]=v;
                if(rear==MAXN)rear=0;
                dep[v]=dep[u]+1;
                ++gap[dep[v]];
            }
        }
    }
    int sap(int start, int end)//這裏加了限制,流超過k就直接返回,爲了加快速度
    {
        int res=0;
        BFS(start, end);
        int cur[MAXN];
        int S[MAXN];
        int top=0;
        memcpy(cur, head, sizeof(head));
        int u=start;
        int i;
        while(dep[start]<n)
        {
            if(u==end)
            {
                int temp=oo;
                int inser;
                for(i=0;i<top;i++)
                    if(temp>edge[S[i]].cap)
                    {
                        temp=edge[S[i]].cap;
                        inser=i;
                    }
                for(i=0;i<top;i++)
                {
                    edge[S[i]].cap-=temp;
                    edge[S[i]^1].cap+=temp;
                }
                res+=temp;
                top=inser;
                u=edge[S[top]].from;
            }
            if(u!=end&&gap[dep[u]-1]==0)//出現斷層,無增廣路
                break;
            //if(res>=k) break;//流大於k直接返回
            for(i=cur[u];i!=-1;i=edge[i].next)
                if(edge[i].cap!=0&&dep[u]==dep[edge[i].to]+1)
                    break;
            if(i!=-1)
            {
                cur[u]=i;
                S[top++]=i;
                u=edge[i].to;
            }
            else
            {
                int min=n;
                for(i=head[u];i!=-1;i=edge[i].next)
                {
                    if(edge[i].cap==0)continue;
                    if(min>dep[edge[i].to])
                    {
                        min=dep[edge[i].to];
                        cur[u]=i;
                    }
                }
                --gap[dep[u]];
                dep[u]=min+1;
                ++gap[dep[u]];
                if(u!=start)u=edge[S[--top]].from;
            }
        }
        return res;
    }
}isap;

int main()
{
    int T;scanf("%d", &T);
    while(T--)
    {
        int n, m;scanf("%d%d", &n, &m);
        int s, t;scanf("%d%d", &s, &t);
        isap.init(n);
        for(int i=1;i<=m;i++)
        {
            int a, b, c;scanf("%d%d%d", &a, &b, &c);
            isap.addedge(a, b, c*(m+1)+1);
        }
        int f=isap.sap(s, t);

        printf("%d\n", f%(m+1));
    }

    return 0;
}

過了09之後,老譚和學弟再開題,我寫1001。這時候發現有一些隊是java過的。。好在求外接圓不復雜,java一發直接過。。。實際這題是考c++高精度浮點數的。據說生成數據時拿一個double和一個高精度對拍,發現double程序的錯誤的數據直接加到數據裏面。。。

1001 Apple

import java.math.BigDecimal;
import java.util.Scanner;
public class Main {

    public static void main(String[] args) {

        BigDecimal x1,x2,x3,x,y1,y2,y3,y,Bx,By,Cx,Cy,D,tm1,tm2,cx,cy,tmp1,tmp2,tmp3,tmp4,dis1,dis2;
        Scanner cin=new Scanner(System.in);
        int T;T=cin.nextInt();
        while(T>0)
        {
            x1=cin.nextBigDecimal();y1=cin.nextBigDecimal();
            x2=cin.nextBigDecimal();y2=cin.nextBigDecimal();;
            x3=cin.nextBigDecimal();y3=cin.nextBigDecimal();
            x=cin.nextBigDecimal();y=cin.nextBigDecimal();

             Bx=x2.subtract(x1); By=y2.subtract(y1);
             Cx=x3.subtract(x1); Cy=y3.subtract(y1);
             D=BigDecimal.valueOf(2).multiply((Bx.multiply(Cy).subtract(By.multiply(Cx))));
             tm1=( Bx .multiply(Bx).add(By.multiply(By)));
             tm2=( Cx .multiply(Cx).add(Cy.multiply(Cy)));


             cx=(Cy.multiply(tm1).subtract(By.multiply(tm2))).divide(D).add(x1);
             cy=(Bx.multiply(tm2).subtract(Cx.multiply(tm1))).divide(D).add(y1);

             tmp1=x.subtract(cx);
             tmp2=y.subtract(cy);
             tmp3=cx.subtract(x1);
             tmp4=cy.subtract(y1);

             dis1=(tmp1.multiply(tmp1).add(tmp2.multiply(tmp2)));
             dis2=(tmp3.multiply(tmp3).add(tmp4.multiply(tmp4)));

            int res=dis1.compareTo(dis2);
            if(res==1) System.out.println("Accepted");
            else System.out.println("Rejected");

            T--;
        }
        cin.close();
    }
}

我之前遇到過Java爆內存的情況。。這次還好沒卡。。。

比賽過去了2h。。確定還有兩道可做題,03和10。。03是個字符串,我和學弟再看。開始死亡之題。。。上來我就有想法,拿最長串去匹配,看前面的串是否出現過就好。。學弟想了個ac自動機做法,瘋狂T。。我加了讀入優化,MLE。。。不是很懂O(len) 的做法爲什麼會T。。我換成了我的AC自動機,其實就是kuangbin的統計單詞個數那題的板子,順便學弟用的string改成char*,終於在兩小時後過了。。。這一個破題卡了兩個小時,也是醉了。賽後據說這題只卡ac自動機,kmp甚至strstr的暴力都能過。。。

更神奇的是,時限3s我2995ms。。。歐皇算法。。。

1003 The Dominator of Strings

#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<algorithm>
#include<queue>
using namespace std;

struct Trie
{
    int next[100010][26], fail[100010], end[100010];
    int root, L;
    int newnode()
    {
        for(int i=0;i < 26;i++)
            next[L][i]=-1;
        end[L++]=0;
        return L-1;
    }
    void init()
    {
        L=0;
        root=newnode();
    }
    void insert(char buf[])
    {
        int len=strlen(buf);
        int now=root;
        for(int i=0;i < len;i++)
        {
            if(next[now][buf[i]-'a']==-1)
                next[now][buf[i]-'a']=newnode();
            now=next[now][buf[i]-'a'];
        }
        end[now]++;
    }
    void build()
    {
        queue<int>Q;
        fail[root]=root;
        for(int i=0;i < 26;i++)
            if(next[root][i]==-1)
                next[root][i]=root;
            else
            {
                fail[next[root][i]]=root;
                Q.push(next[root][i]);
            }
        while(!Q.empty())
        {
            int now=Q.front();
            Q.pop();
            for(int i=0;i < 26;i++)
                if(next[now][i]==-1)
                    next[now][i]=next[fail[now]][i];
                else
                {
                    fail[next[now][i]]=next[fail[now]][i];
                    Q.push(next[now][i]);
                }
        }
    }
    int query(char buf[])
    {
        int len=strlen(buf);
        int now=root;
        int res=0;
        for(int i=0;i < len;i++)
        {
            now=next[now][buf[i]-'a'];
            int temp=now;
            while(temp!=root)
            {
                res+=end[temp];
                end[temp]=0;
                temp=fail[temp];
            }
        }
        return res;
    }
}ac;
char s[100007], ss[100007];
int ls, lss;
int main()
{//freopen("input.txt","r",stdin);

    int T;
    scanf("%d", &T);
    while(T--)
    {
        ls=lss=0;
        int n;scanf("%d ", &n);
        ac.init();
        for(int i=0;i<n;i++)
        {
            gets(s);
            int len=strlen(s);
            if(len>lss)
            {
                strcpy(ss, s);
                lss=len;
            }
            ac.insert(s);
        }
        ac.build();
        int res=ac.query(ss);
        if(res==n) puts( ss);
        else puts("No");
    }
    //system("pause");
    return 0;
}

寫這題的過程中還打出一波單線程,在優化讀入的我沒時間去搞1010。老譚也不是很會數據結構,一直在試圖暴力1010。最後過了這題只剩1小時了,三個人一起上1010。推了半天也沒什麼眉目,最後我和學弟都暴力,他怎麼做的我忘了,反正我在模擬鏈表。因爲我們猜了個結論,就是暴力刪不會有需要遍歷很多次的情況。開始寫的時候就剩半小時了,我模擬鏈表也不是很熟練,最終也沒寫出來。。gg

賽後知道了03連暴力的strstr都能過,就卡ac自動機,我能過純屬歐氣十足。而10我們已經想到正解,就是模擬鏈表。。。感覺自己還是太菜了,1003過的慢,1010沒立刻就有思路。。

還剩兩場,加油!!

發佈了169 篇原創文章 · 獲贊 3 · 訪問量 4萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章