寒假牛客第五场

A-炫酷双截棍
 

题目描述

小希现在手里有一个连着的两块木条,长度分别为l1l1,l2l2,木条之间有一个无摩擦的连接点,木条之间可以相互转动,小希将其称之为双截棍。

现在小希把长为l1l1的木条的一端放在原点(0,0),任意转动这两根木条,小希想知道,是否有可能通过一种转动方式使得双截棍的另一端到达指定点呢?
 

如果不能,请输出所有能到达的点中离目标点最近的距离。

输入描述:

第一行输入一个两个正整数l1,l2,表示木条长度。

第二行输入一个正整数T,表示询问次数。

随后T行,每行两个实数xi,yi表示目标点的坐标。

l1,l2≤1000

T≤1000

|x|,|y|≤10000

输出描述:

对于每次询问,如果可以到达,输出0,如果无法到达,给出所有能到达的点中离目标点最近的距离。

你的答案将被认为是正确的,如果相对误差不大于1e-6。

示例1

输入

复制

23 13
3
15 1
40 0
0 0

输出

复制

0.00000000
4.00000000
10.00000000

签到题,只需判断原点到给出点的距离比两个棍的长度的和大或者比两个棍的长度的差小,就不能达到,否则就可以。

#include<bits/stdc++.h>
#define exp 1e-8
#define mian main
#define pii pair<int,int>
#define pll pair<ll,ll>
#define ll long long
#define pb push_back
#define PI  acos(-1.0)
#define inf 0x3f3f3f3f
#define w(x) while(x--)
#define int_max 2147483647
#define lowbit(x) (x)&(-x)
#define gcd(a,b) __gcd(a,b)
#define pq(x)  priority_queue<x>
#define ull unsigned long long
#define sc(x) scanf("%d",&x)
#define scl(x) scanf("%lld",&x)
#define pl(a,n) next_permutation(a,a+n)
#define ios ios::sync_with_stdio(false)
#define met(a,x) memset((a),(x),sizeof((a)))
using namespace std;
double l1,l2,ans;
int main()
{
    while(~scanf("%lf%lf",&l1,&l2)){
        int t;
        sc(t);
        double x,y;
        while(t--){
            scanf("%lf%lf",&x,&y);
            double sum=sqrt(x*x+y*y);
            if(sum>l1+l2)
                printf("%.8f\n",sum-l1-l2);
            else if(sum<abs(l1-l2))
                printf("%.8f\n",abs(l1-l2)-sum);
            else printf("0.00000000\n");
        }
    }
}

D-炫酷路途

题目描述

小希现在要从寝室赶到机房,路途可以按距离分为N段,第i个和i+1个是直接相连的,只需要一秒钟就可以相互到达。

炫酷的是,从第i个到第i+2pi+2p个也是直接相连的(其中p为任意非负整数),只需要一秒钟就可以相互到达。

更炫酷的是,有K个传送法阵使得某些u,v之间也是直接相连的,只需要一秒钟就可以相互到达,当然,由于设备故障,可能会有一些u=v的情况发生。

现在小希为了赶路,她需要在最短的时间里从寝室(编号为1)到达机房(编号为N),她不希望到达这N个部分以外的地方(不能到达位置N+1),也不能走到比自己当前位置编号小的地方(比如从5走到3是非法的)。

她想知道最短的时间是多少。

输入描述:

第一行输入两个整数N,K,表示路途的段数和传送法阵的数量。

从第二行开始K行,每行两个整数aiai,bibi表示两个位置之间相连。
2≤N≤1,000,000,0002≤N≤1,000,000,000

0≤K≤150≤K≤15

输出描述:

输出一个整数,表示从寝室到机房最短的时间是多少秒。

示例1

输入

复制

12 2
1 5
6 6

输出

复制

3

示例2

输入

复制

17 2
2 5
8 9

输出

复制

1

这个题让我明白了二进制还可以这么用......之前二进制接触的太少了。

1e9的范围,也就2的30多次方,如果不用传送阵,也就是说走30多步即可到达。

那具体的怎么求呢?

把两个点的距离转换成二进制,二进制中有几个1就需要走几步,因为可以一下走2的次方的距离,所以二进制有几个1就说明要走多少步。可以用lowbit(x)来求,就是x & -x,求的是x中最低位的1,例如:6(110),lowbit(6)=2=2^1,上次用到lowbit还是在学树状数组的时候......

如果用传送阵,K<=15,最多的情况也就是2^15种情况,可以枚举出来,从0到2^15依次是不用传送阵,用第一个,用第二个,用第一个和第二个......

具体看代码

#include<bits/stdc++.h>
#define exp 1e-8
#define mian main
#define pii pair<int,int>
#define pll pair<ll,ll>
#define ll long long
#define pb push_back
#define PI  acos(-1.0)
#define inf 0x3f3f3f3f
#define w(x) while(x--)
#define int_max 2147483647
#define lowbit(x) (x)&(-x)
#define gcd(a,b) __gcd(a,b)
#define pq(x)  priority_queue<x>
#define ull unsigned long long
#define sc(x) scanf("%d",&x)
#define scl(x) scanf("%lld",&x)
#define pl(a,n) next_permutation(a,a+n)
#define ios ios::sync_with_stdio(false)
#define met(a,x) memset((a),(x),sizeof((a)))
using namespace std;
const int N=1e9+10;
int n,k;
struct node
{
    int u;
    int v;
}p[20];
int step(int x)
{
    int ans=0;
    while(x){
        x-=lowbit(x);
        ans++;
    }
    return ans;
}
bool cmp(node x,node y)
{
    return x.u<y.u;
}
int main()
{
    while(~scanf("%d%d",&n,&k)){
        for(int i=0;i<k;i++)
            scanf("%d%d",&p[i].u,&p[i].v);
        sort(p,p+k,cmp);
        int ans=step(n-1);
        for(int i=0;i<1<<k;i++){  //这里就是那最多2^15次的情况,
              int t=1,sum=0;
            for(int j=0;j<k;j++)  { //这里是枚举每个传送阵
                if(i&j<<k){           //i&1<<j 的意思是在这第i种情况下是否要用第j个传送阵
                    if(t>p[j].u)
                        continue;
                    sum+=step(p[j].u-t)+1;
                    t=p[j].v;
                }
            }
            if(t>n)
                continue;
                sum+=step(n-t);
            ans=min(ans,sum);
        }
        printf("%d\n",ans);
    }
}

G-炫酷数字

题目描述

小希希望你构造一个最小的正整数,使得其有n个因子。

输入描述:

第一行一个整数T表示数据组数

每组数据第一行输入一个正整数n,表示其因子数。

n≤1,000,000n≤1,000,000

T≤1,000,000T≤1,000,000

输出描述:

输出一行一个整数,表示你构造出的这个数。注意:你需要保证你构造的数≤1,000,000≤1,000,000,如果在这个范围里面无法构造出一个正整数满足条件,请输出-1。

示例1

输入

复制

2
4
5

输出

复制

6
16

这个想到了质数唯一分解定理,然后就T了。。。

原来可以先把1e6次方的范围内的数的因子数先预处理出来,直接查询即可...orz

#include<bits/stdc++.h>
#define exp 1e-8
#define mian main
#define pii pair<int,int>
#define pll pair<ll,ll>
#define ll long long
#define pb push_back
#define PI  acos(-1.0)
#define inf 0x3f3f3f3f
#define w(x) while(x--)
#define int_max 2147483647
#define lowbit(x) (x)&(-x)
#define gcd(a,b) __gcd(a,b)
#define pq(x)  priority_queue<x>
#define ull unsigned long long
#define sc(x) scanf("%d",&x)
#define scl(x) scanf("%lld",&x)
#define pl(a,n) next_permutation(a,a+n)
#define ios ios::sync_with_stdio(false)
#define met(a,x) memset((a),(x),sizeof((a)))
using namespace std;
const int N=1e6+10;
int num[N],vis[N];
void init()         //预处理
{
    for(int i=1;i<N;i++){
    for(int j=i;j<N;j+=i)
        num[j]++;
        if(!vis[num[i]])     //vis数组用来求最小的M
            vis[num[i]]=i;
    }
}
int main()
{
    met(vis,0);
    met(num,0);
    init();
    int n,t;
    sc(t);
    while(t--){
        sc(n);
        if(!vis[n])
            printf("-1\n");
        else printf("%d\n",vis[n]);
    }
}

I-炫酷镜子

链接:https://ac.nowcoder.com/acm/contest/331/I
来源:牛客网
 

题目描述

小希拿到了一个镜子块,镜子块可以视为一个N x M的方格图,里面每个格子仅可能安装`\`或者`/`的镜子,会反射90°光线,也可能没有安装镜子,使用`.`代替。

但她看不清楚里面的镜子构造是怎样的。

你是这块镜子块的主人,所以你想计算这块镜子块(从输入的上方往下射入光线)从左到右每一格射入依次分别会从最下面的哪一格子射出,如果无法射出,输出-1。

输入描述:

第一行输入两个整数N,M。随后的N行,每行M个字符。

1≤N,M≤5001≤N,M≤500

输出描述:

输出M行整数,依次为从第i个格子从上往下射入时从下面的哪里射出,如果光线不会从下面射出,则输出-1。

示例1

输入

复制

3 3
...
...
\.\

输出

复制

3
2
-1

说明

第一列遇到镜子两次反弹通过第三列射出。

第二列直接射出。

第三列因为镜子反弹后向右边射出。

就是个模拟,可能细节多一点

#include<bits/stdc++.h>
#define exp 1e-8
#define mian main
#define pii pair<int,int>
#define pll pair<ll,ll>
#define ll long long
#define pb push_back
#define PI  acos(-1.0)
#define inf 0x3f3f3f3f
#define w(x) while(x--)
#define int_max 2147483647
#define lowbit(x) (x)&(-x)
#define gcd(a,b) __gcd(a,b)
#define pq(x)  priority_queue<x>
#define ull unsigned long long
#define sc(x) scanf("%d",&x)
#define scl(x) scanf("%lld",&x)
#define pl(a,n) next_permutation(a,a+n)
#define ios ios::sync_with_stdio(false)
#define met(a,x) memset((a),(x),sizeof((a)))
using namespace std;
int n,m;
char a[505][505];
void dfs(int x,int y,int z)  //x,y为坐标,z代表方向,1指从上往下,2:从下往上,3:从左往右,4:从右向左
{
    if(x>n){
        printf("%d\n",y);
        return ;
    }
    else if(x<1||y<1||y>m){
        printf("-1\n");
        return ;
    }
    if(z==1){
            int i;
    for(i=x;i<=n;i++){
        if(a[i][y]=='.')
            continue;
        else if(a[i][y]=='/'){
                if(y==1){
                    printf("-1\n");
                    break;
                }
            dfs(i,y-1,4);
            break;
        }
        else{
                if(y==m){
                    printf("-1\n");
                    break;
                }
                dfs(i,y+1,3);
                break;
            }
    }
    if(i==n+1&&a[n][y]=='.'){
    printf("%d\n",y);
    return ;
    }
}
    else if(z==2){
            int i;
        for(i=x;i>=1;i--){
            if(a[i][y]=='.')
            continue;
          else if(a[i][y]=='/'){
                if(y==m){
                    printf("-1\n");
                    break;
                }
            dfs(i,y+1,3);
            break;
          }
          else {
                if(y==1){
                    printf("-1\n");
                    break;
                }
            dfs(i,y-1,4);
            break;
          }
        }
        if(i==0&&a[1][y]=='.'){
            printf("-1\n");
            return ;
        }
    }
    else if(z==3){
        int i;
        for(i=y;i<=m;i++){
            if(a[x][i]=='.')
                continue;
            else if(a[x][i]=='/'){
                    if(x==1){
                        printf("-1\n");
                        break;
                    }
                dfs(x-1,i,2);
                break;
            }
            else {
                    if(x==n){
                        printf("%d\n",i);
                        break;
                    }
                dfs(x+1,i,1);
                break;
            }
        }
        if(i==m+1&&a[x][m]=='.'){
            printf("-1\n");
            return ;
        }
    }
    else {
        int i;
        for(i=y;i>=1;i--){
            if(a[x][i]=='.')
                continue;
            else if(a[x][i]=='/'){
                    if(x==n){
                        printf("%d\n",i);
                        break;
                    }
                dfs(x+1,i,1);
                break;
            }
            else {
                    if(y==1){
                        printf("-1\n");
                        break;
                    }
                dfs(x-1,i,2);
                break;
            }
        }
        if(i==0&&a[x][1]=='.'){
            printf("-1\n");
            return ;
        }
    }
}
int main()
{
    while(cin>>n>>m){
            char c=getchar();
        for(int i=1;i<=n;i++)
            for(int j=1;j<=m;j++)
            cin>>a[i][j];
        for(int i=1;i<=m;i++){
            dfs(1,i,1);
        }
    }
}

J-炫酷数学

链接:https://ac.nowcoder.com/acm/contest/331/J
来源:牛客网
 

题目描述

小希最近想知道一个东西,就是A+B=A|B(其中|为按位或)的二元组有多少个。

当然,直接做这个式子对小希来说太难了,所以小希改变了一些条件,她仅想知道其中A,B<NA,B<N的情况,其中N为2的幂次。

当然,(A=1,B=0)和(A=0,B=1)被认为是不同的二元组。

输入描述:

第一行输入一个非负整数M。

N=2M,M≤100N=2M,M≤100

 

即2的M次为N。

输出描述:

一个整数ans,对998244353取模。

示例1

输入

复制

0

输出

复制

1

示例2

输入

复制

71

输出

复制

588378066

其实打个表,很容易发现答案其实就是3^m。

如果不是找规律,也可以发现二进制中,每一位只有00,01,10三种情况,2^m次方,就是二进制一共有m位,也就是3^m次方

#include<bits/stdc++.h>
#define exp 1e-8
#define mian main
#define pii pair<int,int>
#define pll pair<ll,ll>
#define ll long long
#define pb push_back
#define PI  acos(-1.0)
#define inf 0x3f3f3f3f
#define w(x) while(x--)
#define int_max 2147483647
#define lowbit(x) (x)&(-x)
#define gcd(a,b) __gcd(a,b)
#define pq(x)  priority_queue<x>
#define ull unsigned long long
#define sc(x) scanf("%d",&x)
#define scl(x) scanf("%lld",&x)
#define pl(a,n) next_permutation(a,a+n)
#define ios ios::sync_with_stdio(false)
#define met(a,x) memset((a),(x),sizeof((a)))
using namespace std;
const int mod=998244353;
int m;
ll ksm(ll j,ll k,ll l)
{
    long long ans=1;
    j%=l;
    while(k){
        if(k&1)
            ans=(ans*j)%l;
        j=(j*j)%l;
        k>>=1;
    }
    return ans;
}
int main()
{
    while(~scanf("%d",&m)){
        ll ans=ksm(3,m,mod);
            printf("%lld\n",ans);
    }
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值