A題
It's clear that the leftmost soldier with the maximum height should be the first and the rightmost soldier with the minimum height should be the
last. Thus we will minimize the number of swaps. And the answer is number of leftmost soldier with the maximum height - 1 + n - number
of rightmost soldier with the minimum height. And if the leftmost soldier with the maximum height is more right then the rightmost soldier with the minimum height we should subtract one from the answer.
B題,昨晚題目沒看懂,先做的C題,後來胡亂弄個代碼,提交Pretest,最後是被測掛了。
題意: 一個x-y軸,-1000到1000,有n<=1000個圓,有一個矩形,問矩形的邊界上的點有多少個沒有被圓覆蓋(點在圓邊界上也算覆蓋),保證所有的數字都是整數,即半徑r是整數,點都是整點。
注意英文裡的perimeter除了表示周長的意思,還可以表示邊界,這導致我讀題很混亂。
昨天的想法是,每個圓迴圈判定所有的點,時間複雜度O( n* num of point ),不知為何昨晚估算有4000個點,結果測掛了,今天重寫到8000個點就ac了,My Code還是貼下,裡面有eps,注意了。 還貼上一個人的代碼,值得借鑒。
針對下面另一個人的代碼,我又在文章裡看到一句話:
Useful hint:
For comparing distances you dont need to get square root, you can compare squares => no doubles + no sqrt.
hypot() is slow
覺得很受用,所以以後得注意了。。。
我的:
/*Jan 19, 2012 5:33:54 PM yimao B-Meeting GNU C++ Accepted 220ms 1400KB*/#include <cstdio>#include <cstring>#include <cmath>#include <iostream>#include <algorithm>using namespace std;#define MM(a,b) memset(a,b,sizeof(a));typedef unsigned long long u64;typedef long long lld;#define maxn#define eps (1e-6)int x[8050],y[8050];bool f[8050];int rx,ry,r;bool judge(int i){ if( ( sqrt( 0.0+ (rx-x[i])*(rx-x[i]) + (ry-y[i])*(ry-y[i]) ) - r )< eps ) return 1; else return 0;}int main(){ //freopen("B.txt","r",stdin); int n,i,xa,xb,ya,yb; while(cin>>xa>>ya>>xb>>yb){ int N=0; MM(f,0); int st_x= min(xa,xb), ed_x= max(xa,xb); int st_y= min(ya,yb), ed_y= max(ya,yb); for(i=st_x;i<=ed_x;++i) x[++N]= i, y[N]= st_y; for(i=st_x;i<=ed_x;++i) x[++N]= i, y[N]= ed_y; for(i=st_y+1;i<ed_y;++i) x[++N]= st_x, y[N]= i; for(i=st_y+1;i<ed_y;++i) x[++N]= ed_x, y[N]= i; //printf("N=%d\n",N); cin>>n; while(n--){ scanf("%d%d%d",&rx,&ry,&r); for(i=1;i<=N;++i) if( !f[i] ){ if( judge(i)==1 ){ f[i]=1; } } } int ans=0; for(i=1;i<=N;++i) if( !f[i] ) ans++; printf("%d\n",ans); }}
一個大牛的:
#include <iostream>#include <cstdio>#include <sstream>#include <string>#include <cstring>#include <vector>#include <cmath>#include <cstdlib>#include <ctime>#include <algorithm>#include <map>#include <set>#include <bitset>#include <queue>#define zero(a) (abb(a)<eps)#define lowbit(a) ((a)&(-(a)))#define min(a,b) ((a)<(b)?(a):(b))#define max(a,b) ((a)>(b)?(a):(b))#define abb(a) ((a)>0?(a):(-(a)))#define cj(x1,y1,x2,y2) ((x1)*(y2)-(x2)*(y2))#define dj(x1,y1,x2,y2) ((x1)*(y1)+(y1)*(y2))#define dis(x1,y1,x2,y2) (((x2)-(x1))*((x2)-(x1))+((y2)-(y1))*((y2)-(y1)))const double eps = 1e-9;const int oo = 1000000000;const double E = 2.7182818284590452353602874713527;const double pi = 3.1415926535897932384626433832795;using namespace std;int x[1001],y[1001],r[1001];int n;bool check(int px,int py){ for (int i=1;i<=n;i++) if (dis(px,py,x[i],y[i])<=r[i]*r[i]) return 0; return 1;}int main(){ int x1,y1,x2,y2,s=0; cin>>x1>>y1>>x2>>y2>>n; for (int i=1;i<=n;i++) cin>>x[i]>>y[i]>>r[i]; for (int i=min(x1,x2);i<=max(x1,x2);i++) s+=check(i,y1)+check(i,y2); for (int i=min(y1,y2)+1;i<max(y1,y2);i++) s+=check(x1,i)+check(x2,i); cout<<s<<endl; return 0;}
C題,
I wanted to solve problem C with the idea most contestants did. To have an array of size 26 for S & P and then processing it. My big mistake was that I taught
it would get TLE. Can someone explain me the time of this idea???
Reply:
The time is O(|S| * Aplhabet). Because you take |T| - |S| strings and check them with time
O(Alphabet).
So time is O((|T| - |S|) * Aplhabet) = O(|S| * Alphabet).
You can get TL if you work with strings and get new string using substr, delete or something other, that works O(|S|).
然後在哦我看完blog後才知道,My Code中一個對 ? 的計數是完全多餘的,真的是多餘的,見下面的標程分析:
Let's count number of each letter in the second string and save it, for example, in array a[1..26].
For the first strings' prefix of lengthn,
where n is the length of second string,
(it's the first substring) we count number of each letter in array b[1..26].
We don't count characters ``\texttt{?}''. If there are b[i] ≤ a[i] for
all i, then it's good substring. Then go
to the second substring: subtract from the array b the
first character: b[s[1] - 'a' + 1] – and
add n + 1 character: b[s[n + 1] - 'a' + 1] + + .
If some of these characters is ``\texttt{?}'' then we shouldn't do for it the subtraction or addition. Then repeat the showed check and go to the next substring. Let's repeat this procedure for all substrings of length n.
D題
給n個點,m條賦權邊,n<=10^5, m= min( 10^5, n*(n+1)/2 );,一個頂點s,一個距離值L,問距離頂點s的距離為L的位置的個數,包含頂點和邊上的某點。
首先,Dijkstra + set 求每個點到s的最短路。
然後統計cnt:
1、對於每個點,如果dis[ point ] == L, cnt++;
2、對於每條邊,如果:
dis[u]<L && dis[u]+w>L && dis[u]+w-L+dis[v]>L,則cnt ++;
dis[v]<L && dis[v]+w>L && dis[v]+w-L+dis[u]>L,則cnt++;
dis[u]<L && dis[v]<L && dis[v]+dis[u]+w == L+L,則cnt++;
/*Jan22, 2012 7:56:32 PM yimao D-Missile Silos GNU C++ Accepted 170ms10200KB*/#include <cstdio>#include <cstring>#include <cmath>#include <iostream>#include <algorithm>#include <set>using namespace std;#define MM(a,b) memset(a,b,sizeof(a));typedef unsigned long long u64;typedef long long lld;#define maxn 200050const int maxint= 2000000000;int top;struct Edge{ int u,v,w; Edge *next;}*adj[maxn], edge[maxn];int ux[maxn],vx[maxn],wx[maxn];int n,m,s,L;void Add_edge(int u,int v,int w){ Edge *ptr= &edge[++top]; ptr->u= u, ptr->v= v, ptr->w= w; ptr->next= adj[u]; adj[u]= ptr;}// Dijkstra + set, can count |V|<10^5,|E|<10^5;int dis[maxn];bool use[maxn];struct cmp{ bool operator()(int i,int j)const{ return dis[i]<dis[j] || (dis[i]==dis[j]&&i<j); }};set<int,cmp>Q;void Dijkstra(){ for(int i=1;i<=n;++i) dis[i]= maxint, use[i]=0; dis[s]=0; if( !Q.empty() ) Q.clear(); Q.insert( s ); while( !Q.empty() ){ int u= *Q.begin(); use[u]= 1; Q.erase( u ); for( Edge *p= adj[u];p;p=p->next ){ int v= p->v; if( use[v]==0 && dis[v]> dis[u]+ p->w ){ Q.erase( v ); dis[v]= dis[u]+ p->w; //after update v,can it be insert; Q.insert( v ); } } }}int solve(){ int i,cnt=0; for(i=1;i<=n;++i) if( dis[i]==L ) cnt++; for(i=1;i<=m;++i){ int u= ux[i], v= vx[i], w= wx[i]; if( dis[u]<L && dis[u]+w>L && dis[u]+w-L+dis[v]>L ) cnt++; if( dis[v]<L && dis[v]+w>L && dis[v]+w-L+dis[u]>L ) cnt++; if( dis[u]<L && dis[v]<L && dis[v]+dis[u]+w == L+L ) cnt++; } return cnt;}int main(){ //freopen("D.txt","r",stdin); int i,j; while(cin>>n>>m>>s){ top=0; MM( adj, 0 ); for(i=1;i<=m;++i){ int u,v,w; scanf("%d%d%d",&u,&v,&w); ux[i]=u, vx[i]=v, wx[i]=w; Add_edge( u, v, w ); Add_edge( v, u, w ); } /*for(i=1;i<=n;++i){ for(Edge *p= adj[i];p;p= p->next) printf("%d %d %d\n",i,p->v,p->w); puts(""); }*/ cin>>L; Dijkstra(); /*for(i=1;i<=n;++i) printf("%d %d\n",i,dis[i]); puts("");*/ int ans= solve(); cout<<ans<<endl; }}
E題
我是賽後ac的。。。貪心+優先隊列
題意:見題目
分析:首先題目規定必須是走最短路到達對角線,那麼可以確定對於任意對角線上的格子,一定是其右下角的sportmen到達該格。所有sportmen按y排降序,按x排升序,然後我們對最後一行,把所有在最後一行的sportman加入優先隊列(優先隊列以x為第一關鍵字排升序),隊首元素即是我們需要的,然後對倒數第二行,把所有倒數第二行的sportman加入優先隊列,取隊首元素,看隊首元素是否在對角線點的右下方,在則表示取該點,否則不取,pop之,再取top。。。。。貪心下去就是了,
/*Jan24,2012 12:47:21 PM yimao E-Competition GNU C++ Accepted 170ms 5300KB*/#include <cstdio>#include <cstring>#include <cmath>#include <iostream>#include <algorithm>#include <queue>using namespace std;#define MM(a,b) memset(a,b,sizeof(a));typedef unsigned long long u64;typedef long long lld;#define maxn 100050int n,m;struct Node{ int x,y,index; bool operator<(Node a)const{ return y>a.y || (y==a.y&&x<a.x); }}node[maxn];int c[maxn];struct Temp_Node{ int x,y,index; bool operator<(Temp_Node a)const{ return x>a.x|| (x==a.x&&y>a.y); //////be careful for priority_queue; }};priority_queue<Temp_Node>Q;int main(){ //freopen("E.txt","r",stdin); int i,j; while(cin>>n>>m){ for(i=1;i<=m;++i){ scanf("%d%d",&node[i].x, &node[i].y); node[i].index= i; } sort( node+1, node+1+m ); while( !Q.empty() ) Q.pop(); int ans=0, index=1; for(i=1;i<=n;++i){ for(;index<=m;++index){ if( node[index].y>= (n+1-i) ){ Temp_Node tmp; tmp.x= node[index].x, tmp.y= node[index].y; tmp.index= node[index].index; Q.push( tmp ); } else break; } while( !Q.empty() ){ Temp_Node tmp= Q.top(); Q.pop(); //printf("oo i=%d %d %d\n", i,tmp.x, tmp.index); if( tmp.x<i ) continue; c[ ++ans ]= tmp.index; break; } } printf("%d\n",ans); for(i=1;i<=ans;++i){ printf("%d",c[i]); if( i==ans ) puts(""); else printf(" "); } }}