【URAL 刷题记】URAL 1028 ~ URAL 1035

URAL 1028

/*
题意:求左下角点的个数。。。
题解:把点按照x坐标排序,y轴建一棵树状数组即可。。
*/ 
#include<algorithm>
#include<cstdio>
using namespace std;

typedef pair<int,int>P;


const int MAXN=40000;
int T[MAXN];
void add(int x, int v){ for(; x<MAXN; x+=x&-x) T[x]+=v; }
int sum(int x){ int v=0; for(;x;x-=x&-x) v+=T[x]; return v; }

const int maxn=15010;

P A[maxn];
int res[maxn];
int n;

int main(){
//  freopen("in.txt","r",stdin);
    scanf("%d",&n);
    for(int i=0;i<n;++i){
        int x,y;scanf("%d%d",&x,&y); ++x,++y;
        A[i]=P(x,y);
    }
    sort(A,A+n);
    for%53C%"5�Fspan>(int i=0;i<n;++i){
        int x=sum(A[i].second);
        res[x] ++;
        add(A[i].second,1);
    }
    for(int i=0;i<n;++i)printf("%d\n",res[i]);
//  for(;;);
    return 0;
}

URAL 1029

/*
题意:求出从第一层楼到第m层楼的最少花费, i-1楼的k房间可以到i楼的k房间, 同一楼层相邻的房间可以联通(差1)
题解:直接对每一层往右往左刷一遍(因为权值为正,所以不可能绕弯。),上下更新一把即可。 
*/

#include<algorithm>
#include<cstdio>
#include<cstring>
using namespace std;

typedef long long LL;

const int maxn=10010;

int n,m;
int A[maxn][maxn], f[maxn][maxn], g[maxn][maxn];

void dfs(int d,int i,int j){
    if(i==0)return;
    if(g[i][j]!=j)dfs(d+1,i,g[i][j]); else dfs(d+1,i-1,j);
    printf("%d%c", j,d==0?'\n':' ');
}
void solve(){
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;++i)
        for(int j=1;j<=m;++j)
            scanf("%d",&A[i][j]);
    for(int j=1;j<=m;++j)
        f[0][j]=0;

    for(int i=1;i<=n;++i) {
        for(int j=1;j<=m;++j)
            f[i][j]=f[i-1][j]+A[i][j],g[i][j]=j;
        for(int j=m-1;j>=1;--j)
            if(f[i][j]>f[i][j+1]+A[i][j])
                f[i][j]=f[i][j+1]+A[i][j],g[i][j]=j+1;
        for(int j=2;j<=m;++j)
            if(f[i][j]>f[i][j-1]+A[i][j])
                f[i][j]=f[i][j-1]+A[i][j],g[i][j]=j-1;
    }
    int x=min_element(f[n]+1,f[n]+m+1)-f[n];
    dfs(0,n,x);
}

int main(){
//  freopen("in.txt","r",stdin);
    solve();
//  for(;;);
    return 0;
}

URAL 1030

/*
给出船只和冰山的经纬度,求出它们之间的距离,并判断其是否大于100
解法:
球面的距离公式:R*acos( sin(x1)*sin(x2)+cos(x1)*cos(x2)*cos(y1-y2) )/2;
这里x是纬度,y是经度,计算之前所有的经纬度都要化为弧度制
R=6875,题目里有给

我是先把球坐标系转化为三维坐标系,然后求角度做的。。。。
https://en.wikipedia.org/wiki/Spherical_coordinate_system 
注意一下这里有两幅图,角度表示是不同的。。。所以可能到时图片公式不配套(Baidu百科好坑。。)
*/
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<cmath>
using namespace std;

const double EarthR=6875.0/2;
const double PI=acos(-1.0);

double sqr(double x){ return x*x; }

char s[4][10], t[4][10];

double getang(char *s){
    double res=0;
    char *p=strtok(s,"^'\"");
    res+=atoi(p);
    p=strtok(0,"^'\"");
    res+=atoi(p)/60.0;
    p=strtok(0,"^'\"");
    res+=atoi(p)/60.0/60.0;
    res=res/180.0*PI;
    return res;
}

double ang[4];
double x[2],y[2],z[2];

void solve(){
    scanf("%*s%*s%*s%*s%*s%*s%*s%*s%*s%s%s%*s%s%s%*s%*s%*s%*s%*s%s%s%*s%s%s%*s",s[0],t[0],s[1],t[1],s[2],t[2],s[3],t[3]);

    for(int i=0;i<4;++i) {
        double a=getang(s[i]);
        switch (t[i][0]) {
            case 'N': ang[i]=a; break;
            case 'S': ang[i]=PI-a; break;
            case 'E': ang[i]=a; break;
            case 'W': ang[i]=-a; break;
        }
    }
//  swap(ang[0],ang[1]);
//  swap(ang[2],ang[3]);
    x[0]=sin(ang[0])*cos(ang[1]), y[0]=sin(ang[0])*sin(ang[1]), z[0]=cos(ang[0]);
    x[1]=sin(ang[2])*cos(ang[3]), y[1]=sin(ang[2])*sin(ang[3]), z[1]=cos(ang[2]);
    double d=sqrt(sqr(x[1]-x[0])+sqr(y[1]-y[0])+sqr(z[1]-z[0]));

    double rad=acos((2-d*d)/2);
    printf("%.2lf\n", EarthR*rad);
}

int main(){
    freopen("in.txt","r",stdin);
    solve();
    for(;;);
    return 0;
}

URAL 1031

/*
题意:火车有三种区间票,花费Ci可以坐Li距离,然后求两点之间最小花费
题解:因为f[]有单调性所以直接二分一把即可。 
*/
#include<algorithm>
#include<cstdio>
#include<cstring>
using namespace std;

constint maxn=10010;

int n,s,t;
int L[3],C[3];
int a[maxn],f[maxn];
void solve(){
    for(int i=0;i<3;++i)scanf("%d",L+i);
    for(int i=0;i<3;++i)scanf("%d",C+i);
    scanf("%d%d%d",&n,&s,&t);
    if(s>t)swap(s,t);
    a[1]=0;
    for(int i=2;i<=n;++i)
        scanf("%d",&a[i]);

    memset(f,0x3f,sizeof f);
    for(int i=1;i<=s;++i)f[i]=0;
    for(int i=s+1;i<=t;++i){
        for(int j=0;j<3;++j){
            int x=lower_bound(a+1,a+1+n,a[i]-L[j])-a;
            if(x==i) continue;
            f[i]=min(f[i],f[x]+C[j]);
        }
    }
    printf("%d\n",f[t]);
}

int main(){
//  freopen("in.txt","r",stdin);
    solve();
//  for(;;);
    return 0;
}

URAL 1032

/*
题意,找出几个数使和能被N整除
解法,累加对N取模,如果有相同的模表示这两个数之间的几个数的和被N整除
(由抽屉原理,模只有1 to N-1(0的时候单个数即可),累加结果有N个,必然存在至少一组相同的模

cao..这题竟然要输出数,而不是数的编号。。。 
*/
#include<algorithm>
#include<cstdio>
#include<cstring>
using namespace std;

typedef long long LL;

const int maxn=10010;

int n;
LL a[maxn], s[maxn];
int no[maxn];
void solve(){
    scanf("%d",&n);
    for(int i=1;i<=n;++i){
        int x; scanf("%d",&x);
        a[i]=x;
    }
    memset(no,255,sizeof no);
    s[ no[0]=0 ] = 0;
    for(int i=1;i<=n;++i){
        if(a[i]%n==0){
            printf("1\n%d\n",a[i]);
            return;
        }
        s[i]=s[i-1]+a[i];
        int x=s[i]%n;
        if(~no[x]){
            printf("%d\n",i-no[x]);
            for(int j=no[x]+1;j<=i;++j)
                printf("%d\n",a[j]);
            return;
        }
        no[x]=i;
    }
    printf("0\n");
}

int main(){
    solve();
//  for(;;);
    return 0;
}

URAL 1033

/*
给一个迷宫图, 墙在#的位置, 或者是迷宫图的四周.但是左上角和右下角没有墙.
问对于一个游客来说, 可以看见的墙的总面积.穿过2个相邻的墙里面的墙是不能被看见的, 2个墙相邻当且仅当这2个墙至少有一个角碰到.

从一个角开始4方向遍历, 走到的所有的地方上下左右看一下有没有墙.
注意要从2个角都跑一遍.
*/
#include<algorithm>
#include<cstdio>
#include<cstring>
using namespace std;

typedef long long LL;

const int maxn=50;

const int dxy[4][2]={{-1,0},{1,0},{0,-1},{0,1}};

int n;

char mp[maxn][maxn];

bool check(int x,int y){ return 0<=x&&x<n&&0<=y&&y<n&&mp[x][y]!='#'; }

bool vis[maxn][maxn];
int res;
void dfs(int x, int y){
    vis[x][y]=1;
    for(int d=0;d<4;++d){
        int X=x+dxy[d][0],Y=y+dxy[d][1];
        if (!vis[X][Y]){
            if(check(X,Y))
                dfs(X,Y);
            else
                ++res;
        }
    }
}

void solve(){
    scanf("%d",&n);
    for(int i=0;i<n;++i)
        scanf("%s",mp[i]);
    res=0;
    memset(vis,0,sizeof vis);
    dfs(0,0); if(!vis[n-1][n-1])dfs(n-1,n-1);
    printf("%d\n",(res-4)*9);
}

int main(){
//  freopen("in.txt","r",stdin);
    solve();
//  for(;;);
    return 0;
}

URAL 1034

/*
题意:给出一个n皇后的方案,要求恰好移动三个皇后且仍不互相攻击的方案数
题解:枚举 每个方案判断新的三个皇后是否相互攻击和与之前的皇后是否相互攻击即可
(好像写的巨烦。。) 
*/
#include<algorithm>
#include<cstdio>
#include<cstring>
using namespace std;

typedef long long LL;

const int maxn=60;

const int dxy[4][2]={{-1,-1},{-1,1},{1,-1},{1,1}};

int n;
int x[maxn],y[maxn];
int mp[maxn][maxn];
int per[maxn];
int p[4];

bool ok(int x,int y){return 1<=x&&x<=n&&1<=y&&y<=n; }
bool check(int x,int y){
    for(int d=0;d<4;++d)
        for(int p=1;;++p){
            int X=x+dxy[d][0]*p,Y=y+dxy[d][1]*p;
            if(ok(X,Y)){
                if(mp[X][Y]==1) return 0;
            }else
                break;
        }
    return 1;
}

void solve(){
    scanf("%d",&n);
    memset(mp,0,sizeof mp);
    for(int i=1;i<=n;++i){
        scanf("%d%d",&x[i],&y[i]);
        mp[x[i]][y[i]]=1;
    }
    int res=0;
    for(p[1]=1;p[1]<=n;++p[1])
        for(p[2]=p[1]+1;p[2]<=n;++p[2])
            for(p[3]=p[2]+1;p[3]<=n;++p[3]){
                mp[x[p[1]]][y[p[1]]]=0;
                mp[x[p[2]]][y[p[2]]]=0;
                mp[x[p[3]]][y[p[3]]]=0;
                for(int i=1;i<=3;++i)per[i]=i;
                do{
                   %2�%3spcn class="hljs-keyword">bool fg=0;
                    for(int i=1;i<=3;++i)if(per[i]==i){ fg=1;break; }
                    if(fg) continue;
                    mp[x[p[1]]][y[p[per[1]]]]=1;
                    mp[x[p[2]]][y[p[per[2]]]]=1;
                    mp[x[p[3]]][y[p[per[3]]]]=1;
                    if(check(x[p[1]],y[p[per[1]]]) && check(x[p[2]],y[p[per[2]]]) && check(x[p[3]],y[p[per[3]]])){
/*                      for(int i=1;i<=n;++i,putchar('\n'))
                            for(int j=1;j<=n;++j,putchar(' '))
                                printf("%d",mp[i][j]);
                        putchar('\n');
*/                      ++ res;
                    }
                    mp[x[p[1]]][y[p[per[1]]]]=0;
                    mp[x[p[2]]][y[p[per[2]]]]=0;
                    mp[x[p[3]]][y[p[per[3]]]]=0;
                } while(next_permutation(per+1,per+1+3));
                mp[x[p[1]]][y[p[1]]]=1;
                mp[x[p[2]]][y[p[2]]]=1;
                mp[x[p[3]]][y[p[3]]]=1;
            }
    printf("%d\n",res);
}

int main(){
//  freopen("in.txt","r",stdin);
    solve();
//  for(;;);
    return 0;
}

URAL 1035

/*
题意:给出一幅十字绣的图案,询问最少的穿针次数(前m*n是正面图案,后m*n是背面图案)
一次穿针的要求�%�C%yA0A1:线头如果从正面穿入,那么必然从正面穿出,而且之后便翻转方向,即从那个位置开始反面穿针。反过来亦如此
2:线头如果到了格点,那么必须翻转方向,而且只能在格点翻转方向
3:针在不反转方向的情况下,一次只能穿1*1的格子的对角线
(好像就这些了,其实就是平常穿针的要求=_=)

解法:这是个一笔画问题,然而却不好建图
于是我们可以考虑从点的度数下手
由于不同的连通块(图案)之间,是无法用同一根针穿起来的,所以我们考虑一个连通块时候的情况,之后再将答案相加
对某个点,定义针需要从正面穿入穿出的为入度,从反面穿入穿出的为出度
那么在一个连通图中,一个点对度数的贡献就是入度和出度之差的绝对值
一个连通块对答案的贡献就是所有点的度数贡献之和除以2,如果之和为0的话那么贡献就是1.
*/

#include<algorithm>
#include<cstdio>
#include<cstring>
using namespace std;

typedef long long LL;

const int maxn=210;

char mp0[maxn][maxn];
int mp[maxn][maxn], fg[maxn][maxn];
int n,m;

void read(int v){
    for(int i=0;i<n;++i)
        for(int j=0;j<m;++j){
            char x; scanf(" %c",&x);

            if(mp0[i][j]=='.') mp0[i][j]=x;
            else if((mp0[i][j]=='/' && (x=='\\' || x=='X')) || (mp0[i][j]=='\\' && (x=='/' || x=='X')))
                mp0[i][j]='X';

            if(x=='\\'||x=='X'){
                mp[i][j]+=v; mp[i+1][j+1]+=v; fg[i][j]=fg[i+1][j+1]=1;
            }
            if(x=='/'||x=='X'){
                mp[i][j+1]+=v; mp[i+1][j]+=v; fg[i][j+1]=fg[i+1][j]=1;
            }
        }

}

const int dxy[4][2]={{1,-1},{-1,1},{1,1},{-1,-1}};

bool check0(int x,int y){ return 0<=x&&x<n&&0<=y&&y<m; }
bool check(int x,int y){ return 0<=x&&x<=n&&0<=y&&y<=m; }

int s;
bool dfs(int x,int y){
    s+=abs(mp[x][y]);
//  printf("%d %d %d\n",x,y,s);
    fg[x][y]=0;

    if(check0(x,y-1) && (mp0[x][y-1]=='/'||mp0[x][y-1]=='X')){
        int d=0;
        int X=x+dxy[d][0], Y=y+dxy[d][1];
        if(check(X,Y) && fg[X][Y])
            dfs(X,Y);
    }
    if(check0(x-1,y) && (mp0[x-1][y]=='/'||mp0[x-1][y]=='X')){
        int d=1;
        int X=x+dxy[d][0], Y=y+dxy[d][1];
        if(check(X,Y) && fg[X][Y])
            dfs(X,Y);
    }
    if(check0(x,y) && (mp0[x][y]=='\\'||mp0[x][y]=='X')){
        int d=2;
        int X=x+dxy[d][0], Y=y+dxy[d][1];
        if(check(X,Y) && fg[X][Y])
            dfs(X,Y);
    }
    if(check0(x-1,y-1) && (mp0[x-1][y-1]=='\\'||mp0[x-1][y-1]=='X')){
        int d=3;
        int X=x+dxy[d][0], Y=y+dxy[d][1];
        if(check(X,Y) && fg[X][Y])
            dfs(X,Y);
    }
}

void solve(){
    scanf("%d%d",&n,&m);
    for(int i=0;i<n;++i) for(int j=0;j<m;++j) mp0[i][j]='.';
    read(1); read(-1);
    int res=0;
    for(int i=0;i<=n;++i)
        for(int j=0;j<=m;++j)if(fg[i][j]){
            s=0;
            dfs(i,j);
            s=s/2;
//          printf("%d %d %d\n===========\n",i,j,s);
            res+=(s==0?1:s);
        }
    printf("%d\n",res);
}

int main(){
//  freopen("in.txt","r",stdin);
    solve();
//  for(;;);
    return 0;
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值