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。。。不是很懂
更神奇的是,時限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沒立刻就有思路。。
還剩兩場,加油!!