Cf 103 div.2

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了,我的代码还是贴下,里面有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后才知道,我的代码中一个对 ? 的计数是完全多余的,真的是多余的,见下面的标程分析:

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 170ms	10200KB*/
#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 200050
const 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 100050

int 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(" ");
        }
    }
}



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值