http://www.codeforces.com/contest/23
下面B,C都來自iSea大神的題解;
A題
【題意】
給定一個串,求其最長重複子串長度,
【分析】
考慮到長度為100,可以暴力,我考慮到在本機可以貼模板,用尾碼數組寫的,取height數組的最大值輸出即可;
【暴力的好的代碼】
【尾碼數組代碼】
/*Apr2,2011 5:19:02PM yimao A-Youre Given a String... GNUC++ Accepted 30ms 1400KB*/ </p><p>http://codeforces.com/contest/23/problem/A</p><p>#define N 110<br />int r[N],sa[N],rank[N],height[N];<br />int wss[30],wa[N],wb[N],wv[N];<br />int cmp(int *r,int a,int b,int t)<br />{return r[a]==r[b]&&r[a+t]==r[b+t];}<br />void Da(int *r,int *sa,int n,int m){<br /> int i,j,p,*x=wa,*y=wb,*t;<br /> for(i=0;i<m;i++)wss[i]=0;<br /> for(i=0;i<n;i++)wss[x[i]=r[i]]++;<br /> for(i=1;i<m;i++)wss[i]+= wss[i-1];<br /> for(i=n-1;i>=0;i--)sa[--wss[x[i]]]=i;<br /> for(j=1,p=1;p<n;j*=2,m=p){<br /> for(p=0,i=n-j;i<n;i++) y[p++]=i;<br /> for(i=0;i<n;i++)if(sa[i]>=j)y[p++]=sa[i]-j;<br /> for(i=0;i<n;i++)wv[i]=x[y[i]];<br /> for(i=0;i<m;i++)wss[i]=0;<br /> for(i=0;i<n;i++)wss[wv[i]]++;<br /> for(i=1;i<m;i++)wss[i]+= wss[i-1];<br /> for(i=n-1;i>=0;i--)sa[--wss[wv[i]]]=y[i];<br /> for(t=x,x=y,y=t,p=1,x[sa[0]]=0,i=1;i<n;i++)<br /> x[sa[i]]=cmp(y,sa[i-1],sa[i],j)?p-1:p++;<br /> }<br /> return;<br />}<br />void Cal_height(int *r,int *sa,int n){<br /> int i,j,k=0;<br /> for(i=1;i<=n;i++) rank[sa[i]]=i;<br /> for(i=0;i<n;height[rank[i++]]=k)<br /> for(k?k--:0,j=sa[rank[i]-1];r[i+k]==r[j+k];k++); // == ;<br />}<br />int main()<br />{<br /> char ch[110];<br /> while(gets(ch))<br /> {<br /> int n=strlen(ch);<br /> for(int i=0;i<n;i++)r[i]=ch[i]-'a'+1;<br /> r[n]=0;<br /> Da(r,sa,n+1,28);<br /> Cal_height(r,sa,n);<br /> cout<<*max_element(height+2,height+1+n)<<endl;<br /> }<br />}<br />/*<br />abcd<br />ababa<br />zzz<br />*/
B題
【題意】
問n個人蔘加聚會,先把沒有朋友的人驅逐,然後把只有一個朋友的人驅逐,然後把只有兩個朋友的人驅逐……最後把有n-1個朋友的人驅逐,問最後有多少人留在了這次聚會中;
換成圖論裡的話說就是一個無向圖中,去掉度為0的點,然後去掉度為1的點……;
【分析】
答案是n-2,分配方法是n個點取完全圖,然後任意選兩個相連的點,去掉,它們的度為n-1,那麼我們接下來要去的點的度數為n,而剩下的點的度皆是n-3,可以留下來了;
【代碼】
/*Apr24,2011 3:25:51PM yimao B-Party GNU C++ Accepted 230ms 1400KB*/<br />//http://codeforces.com/contest/23/problem/B<br />//from:http://hi.baidu.com/%D2%BB%CE%BB%C1%E3/blog/item/9d7e2a1f1daa70f91ad57618.html<br />int main()<br />{<br /> int T,n;<br /> cin>>T;<br /> while(T--)<br /> {<br /> cin>>n;<br /> if(n<=2) n=0; //注意n<=2時,輸出為0;<br /> else n-=2;<br /> cout<<n<<endl;<br /> }<br />}
C題
【題意】
給定n,然後是n+n-1組數,每組數是一個x,y,要求選出n組數,使得n組數的x之和大於總的x之和的一半,y之和大於總的y之和的一半;
【分析】
從iSea大神那裡學到的方法,好牛!對x從小到大排序,然後對於每兩組數取y更大的那組;
原理嘛,不清楚,但卻是是這樣,自己可以寫下例如n=5,排序後:
x1 y1
x2 y2 (1)
x3 y3
x4 y4 (2)
x5 y5
x6 y6 (3)
x7 y7
x8 y8 (4)
x9 y9
首先我們選y更大的那組,對y是保證滿足條件,下面分析x,從(2)無論選哪個x,一定大於(1)中的兩個x,從(3)中選的x一定大於(2)中的兩個x,……最後是x9一定大於(4)中的x,這樣選我們保證了未選的四個數,都有比之大的數,也就是選出的x的和一定大於總和的一半,這個思想十分值得學習,ORZ!
【代碼】
/*Apr24,2011 4:06:40PM yimao C-Oranges and Apples GNUC++ Accepted 250ms 3700KB*/<br />//http:codeforces.com/contest/23/problem/C<br />//from: http://hi.baidu.com/%D2%BB%CE%BB%C1%E3/blog/item/9d7e2a1f1daa70f91ad57618.html<br />struct Data{<br /> int x,y,idx;<br /> bool operator<(Data t)const{<br /> return x<t.x;<br /> }<br />}a[200020];<br />int main()<br />{<br /> int T,n,i;<br /> cin>>T;<br /> while(T--)<br /> {<br /> cin>>n;<br /> n+= n-1;<br /> for(i=1;i<=n;i++){<br /> scanf("%d%d",&a[i].x,&a[i].y);<br /> a[i].idx=i;<br /> }<br /> sort(a+1,a+1+n);<br /> puts("YES");<br /> for(i=2;i<n;i+=2)<br /> printf("%d ",a[a[i].y>a[i-1].y?i:i-1].idx);<br /> printf("%d/n",a[n].idx);<br /> }<br />}