2021 年百度之星·程序设计大赛 - 初赛三(部分)

链接

数字游戏

Accepts: 7247 Submissions: 13194
Time Limit: 2000/1000 MS (Java/Others)
Memory Limit: 32768/32768 K (Java/Others)

Problem Description

小蜗蜗有 n n n 个数字(实数),但他不知道这些数字具体是啥。

他只知道这 n n n 个数字的最大值、最小值和平均值,但也不一定是对的。

现在,小蜗蜗想知道,存不存在一种方案,使得这 nn 个数字的最大值、最小值和平均值恰好等于给定值。

Input

第一行读入一个整数 t e s t ( 1 ≤ t e s t ≤ 100000 ) test(1\leq test \leq 100000) test(1test100000) 表示数据组数。

接下来 t e s t test test 行,每行四个整数 n , m a x , m i n , a v e ( 1 ≤ n ≤ 100000 , − 100 ≤ m a x , m i n , a v e ≤ 100 ) n, max, min, ave(1 \leq n \leq 100000, -100 \leq max, min, ave \leq 100) n,max,min,ave(1n100000,100max,min,ave100) 分别表示最大值、最小值和平均值。

注意,一开始的 n n n 个数字的取值范围是实数。

Output

输出共 t e s t test test 行。

对于第 i i i 行,如果存在一组合法方案,输出 yes,否则输出 no。

Sample Input

2
3 1 1 1
2 3 1 1

Sample Output

yes
no

思路

首先特判 n = = 1 n==1 n==1 的情况,对于其他情况,计算 n n n 个数之和的最大值 ( n − 1 ) × m a x + m i n (n-1)\times max+min (n1)×max+min,最小值 ( n − 1 ) × m i n + m a x (n-1)\times min+max (n1)×min+max,若 a v g × n avg\times n avg×n 在二者之间,则符合要求,否则不符合。

比较坑的是,输入的 m a x max max 未必比 m i n min min 大,所以需要判断 m a x ≥ a v g ≥ m i n max \geq avg\geq min maxavgmin,若不满足这一条件,直接输出no。

#include<bits/stdc++.h>
#define int long long
using namespace std;
int T,n,mx,mn,avg;

void solve(){
    int mnn,mxn;
    cin>>n>>mx>>mn>>avg;
    if(mx>=mn&&avg<=mx&&avg>=mn){
        if(n==1){
            if(mx==mn&&mn==avg){ cout<<"yes\n"; return; }
            else{ cout<<"no\n"; return; }
        }
        mnn=mxn=mx+mn;
        avg*=n;
        if(n-2>0) mxn+=(n-2)*mx;
        if(n-2>0) mnn+=(n-2)*mn;
        if(avg>=mnn&&avg<=mxn) cout<<"yes\n";
        else cout<<"no\n";
    }else{
        cout<<"no\n";
    }
}

signed main(){
    ios::sync_with_stdio(false);
    for(cin>>T;T;T--) solve();
}

网格路径

Accepts: 735 Submissions: 3776
Time Limit: 2000/1000 MS (Java/Others)
Memory Limit: 32768/32768 K (Java/Others)

Problem Description

给定一张 n × n n\times n n×n 的网格图,有些格子能走,有些格子不能走,左上角的格子坐标为 ( 1 , 1 ) (1,1) (1,1),右下角的格子坐标为 ( n , n ) (n,n) (n,n)

问最多可以找到多少条从 ( 1 , 1 ) (1,1) (1,1) ( n , n ) (n,n) (n,n) 的不相交路径,使得每条路径经过的每个格子(包含 ( 1 , 1 ) (1, 1) (1,1) ( n , n ) (n, n) (n,n))都是能走的格子?

每次我们只可以向右或向下走,不能离开网格图的边界。两条路径不相交当且仅当除了格子 ( 1 , 1 ) (1,1) (1,1) ( n , n ) (n,n) (n,n),它们没有任何公共部分。

Input

第一行一个整数 t e s t ( 1 ≤ t e s t ≤ 1000 ) test(1\leq test \leq 1000) test(1test1000) 表示数据组数。

对于每组数据,第一行一个整数 n ( 2 ≤ n ≤ 10 ) n(2\leq n \leq 10) n(2n10) 表示网格图的大小。

接下来 n n n 行,每行一个长度为 n n n 的字符串。第 i i i 行第 j j j 列的字符 ‘.’ 表示 ( i , j ) (i,j) (i,j) 可以走,’#’ 表示不能走。

Output

对于每组数据,输出一行一个整数表示最多可以找到的不相交路径数目。

Sample Input

3
2
..
..
3
...
.##
...
3
.#.
#..
...

Sample Output

2
1
0

思路

最多有两条路径,所以主要是判断答案为 1 1 1 还是为 2 2 2

可以用深搜找出一条尽量靠右的路,把走过的路标记为已访问。在走一条尽量靠下的路。

特判 m p [ 1 ] [ 1 ] mp[1][1] mp[1][1] m p [ n ] [ n ] mp[n][n] mp[n][n] ,若它们不能走,则答案直接为 0 0 0

#include<bits/stdc++.h>
using namespace std;
const int rdir[2][2]={{0,1},{1,0}};
const int ldir[2][2]={{1,0},{0,1}};
int T,n,vis[20][20];
char mp[20][20];

bool dfs(int x,int y,int flag){
    vis[x][y]=1;    
    for(int k=0;k<2;k++){
        int xx,yy;
        if(flag) xx=x+rdir[k][0],yy=y+rdir[k][1];
        else xx=x+ldir[k][0],yy=y+ldir[k][1];
        if(xx==n&&yy==n) return true;
        if(xx<=n&&y<=n&&x>0&&y>0&&mp[xx][yy]=='.'&&vis[xx][yy]==0){
            vis[xx][yy]=1;    
            if(dfs(xx,yy,flag)) return true;
        }
    }
    return false;
}

void solve(){
    int ans=0;
    scanf("%d",&n);
    memset(vis,0,sizeof(vis));
    for(int i=1;i<=n;i++) scanf("%s",mp[i]+1);
    if(mp[1][1]=='#'||mp[n][n]=='#'){ printf("0\n"); return; }
    if(dfs(1,1,1)) ans++;
    if(dfs(1,1,0)) ans++;
    printf("%d\n",ans);
}

int main(){
    for(scanf("%d",&T);T;T--) solve();
}

虫族基地

Accepts: 195 Submissions: 1613
Time Limit: 2000/1000 MS (Java/Others)
Memory Limit: 32768/32768 K (Java/Others)

Problem Description

有一个 n × m n \times m n×m 的网格,左上角的格子坐标为 ( 1 , 1 ) (1,1) (1,1),右下角的格子坐标为 ( n , m ) (n,m) (n,m)

初始的时候,网格上有两个虫族基地,其中一个在第一行,另一个在最后一行。 对于每个虫族基地,在第 i 2 i^2 i2 秒结束的时候,与虫族基地曼哈顿距离为 i i i 的格子会被虫族占领。

有一批物资要从 ( 1 , 1 ) (1,1) (1,1) 运送到 ( n , m ) (n,m) (n,m),每次我们可以走上下左右四个方向,我们不能离开网格图的边界。

物资经过的路径(包含起终点)不能存在任何被虫族占领的格子(虫族基地也不行)。

请问第几秒结束时,从 ( 1 , 1 ) (1,1) (1,1) ( n , m ) (n,m) (n,m) 的联系会被切断?(不存在一条从左上到右下的路径)

Input

第一行一个正整数 t e s t ( 1 ≤ t e s t ≤ 100000 ) test(1 \le test \le 100000) test(1test100000) 表示数据组数。

对于每组数据,一行四个整数 n , m , x 1 , x 2 ( 1 ≤ n , m ≤ 1000000000 , 1 ≤ x 1 , x 2 ≤ m ) n, m, x_1, x_2(1\le n,m\le 1000000000, 1\le x_1, x_2 \le m) n,m,x1,x2(1n,m1000000000,1x1,x2m)。两个虫族基地的坐标分别为 ( 1 , x 1 ) (1, x_1) (1,x1) ( n , x 2 ) (n, x_2) (n,x2)

Output

对于每组数据,输出一行一个整数表示答案。

Sample Input

3
2 2 2 1
3 3 3 1
3 3 1 1

Sample Output

0
1
0

思路

不断更新道路被切断时间的最小值 m n mn mn 。首先,若是起点 ( 1 , 1 ) (1,1) (1,1) 或是终点 ( n , n ) (n,n) (n,n) 被占领,则被切断;若是蚁群纵向从 1 1 1 占领到 n n n,那么也被切断;计算两个蚁群之间的曼哈顿距离 m h d L e n mhdLen mhdLen ,若是两个蚁群的横坐标相同,那么用 m h d L e n 2 \frac {mhdLen} 2 2mhdLen 更新最小值,否则,用 m h d L e n − 1 2 \frac{mhdLen-1}{2} 2mhdLen1 更新最小值。
最后特判一下最小值会不会小于 0 0 0,若小于 0 0 0,则置零。输出 m n 2 mn^2 mn2

#include<bits/stdc++.h>
#define int long long
using namespace std;
int T,n,m,x,y;

void solve(){
    cin>>n>>m>>x>>y;
    int mn=min(x-1,m-y);
    mn=min(mn,n-1);
    int mhdLen=abs(x-y)+n-1;
    if(x==y) mn=min(mn,(n-1)/2);
    else mn=min(mn,(mhdLen-1)/2);
    if(mn<0) mn=0;
    cout<<mn*mn<<endl;
}

signed main(){
    ios::sync_with_stdio(false);
    for(cin>>T;T;T--) solve();
}

环上游走

Accepts: 535 Submissions: 1166
Time Limit: 2000/1000 MS (Java/Others)
Memory Limit: 32768/32768 K (Java/Others)

Problem Description

有一个环,环上有 n n n 个位置,它们的编号为 1... n 1...n 1...n

位置 i ( 1 < i < n ) i(1 < i < n) i(1<i<n) 左右两边分别是位置 i − 1 i-1 i1 和位置 i + 1 i+1 i+1,位置 1 1 1 左右两边分别是位置 n n n 和位置 2 2 2,位置 n n n 左右两边分别是位置 n − 1 n-1 n1 和位置 1 1 1

现在,我们要玩一个游戏。初始我们在位置 1 1 1,游戏共 n − 1 n-1 n1 轮,对于第 i ( 1 ≤ i < n ) i(1 \le i < n) i(1i<n) 轮,我们可以选择从当前位置往左或往右连续走 i i i 个位置。

现在我们想知道,对于给定的 n n n,有多少种方案,使得我们停留的 n n n 个位置(初始的位置 1 1 1 n − 1 n-1 n1 轮中每一轮结束时候的位置)没有重复。

Input

第一行一个整数 t e s t ( 1 ≤ t e s t ≤ 80 ) test(1 \le test \le 80) test(1test80) 表示数据组数。

对于每组数据,一行一个整数 n ( 1 ≤ n ≤ 80 ) n(1 \le n \le 80) n(1n80) 表示环的大小。

Output

对于每组数据,一行一个整数表示答案。

Sample Input

4
2
3
4
5

Sample Output

2
2
4
2

思路

这题先是深搜交一发,超时了,就打个表,过了。

不过也有别人写的深搜就过了,但是赛后同样的代码再交一次,还会超时。可能是比赛时的测评机有优化。

//深搜超时代码
#include<bits/stdc++.h>
using namespace std;
int T,n,ans;
bitset<80> b;

void dfs(int p,int step){
    if(step==n) return void(ans++);
    int np=p+step; if(np>n) np-=n;
    if(b[np]==0){ b[np]=1; dfs(np,step+1); b[np]=0; } 
    np=p-step+n; if(np>n) np-=n;
    if(b[np]==0){ b[np]=1; dfs(np,step+1); b[np]=0; } 
}

void solve(){
    ans=0; cin>>n;
	b[1]=1,dfs(1,1);
    cout<<ans<<endl;
}

int main(){
    ios::sync_with_stdio(false);
    for(cin>>T;T;T--) solve();
}
#include<bits/stdc++.h>
using namespace std;
int T,n,a[100]={0,1,2,2,4,2,4,4,8,2,4,6,8,2,8,6,16,2,4,6,8,4,12,6,16,4,4,4,16,2,12,10,32,4,4,8,8,2,12,6,16,2,8,6,24,6,12,8,32,6,8,6,8,2,8,10,32,4,4,6,24,2,20,6,64,6,8,8,8,4,16,6,16,2,4,8,24,14,12,6,32};

int main(){
    scanf("%d",&T);
    while(T--){
        scanf("%d",&n);
        printf("%d\n",a[n]);
    }
}
  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

m0_51864047

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值