2019, XII Samara Regional Intercollegiate Programming Contest 解题报告

本文详细介绍了2019年萨马拉区域大学生编程竞赛的题目和解题思路,涵盖多个算法问题,如房间与通道、列重排、圆上的跳跃等。文章提供了每个问题的解决方案和相关代码实现。

2019 XII Samara Regional Intercollegiate Programming Contest

传送门


A. Rooms and Passages

题意:

n + 1 n+1 n+1 个房间, n n n 把钥匙,有第 i i i 把钥匙你可以从房间 i − 1 i-1 i1 走到房间 i i i。每个房间 i i i 都有两种类型中的一种:

  • 一、只有拥有钥匙 a i a_i ai 才能从 i − 1 i-1 i1 走到 i i i
  • 二、从 i − 1 i-1 i1 走到 i i i 之后会失去钥匙 a i a_i ai

现在问你从每个房间出发开始往后走,最远能走几个房间。

题解:

尺取(two pointers),根据走到房间的种类:如果是种类一,则判断所需钥匙数量是否为 1;如果是种类二,则增加当前房间消耗的钥匙数量,并且左端点退出时减少被消耗的钥匙数量。

代码:

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int maxn=500005;
int a[maxn];
int type[maxn];
int tag[maxn];
int ans[maxn];
int main(){
   
   
    int n;scanf("%d",&n);
    for(int i=1;i<=n;i++){
   
   
        int x;scanf("%d",&x);
        if(x>0) a[i]=x,type[i]=1;
        else a[i]=-x,type[i]=2;
    }
    int ed=1;
    for(int st=1;st<=n;st++){
   
   
        while(ed<=n){
   
   
            if(type[ed]==1){
   
   
                if(tag[a[ed]]) break;
            }else{
   
   
                tag[a[ed]]++;
            }
            ed++;
        }
        ans[st]=ed-st;
        if(type[st]==2) tag[a[st]]--;
    }
    for(int i=1;i<=n;i++) printf("%d%c",ans[i],(i==n)?'\n':' ');
    return 0;
}

B. Rearrange Columns

题意:

给定一个 2 ∗ l e n 2*len 2len 的点阵,每个点均为 . . . # \# #,问能否将点阵的每一列重排,使得所有的 # \# # 构成一个联通块。

题解:

显然我们可以分析出,每一列只有第一行是 # \# # 的都可以放到一起,形如:

######
......

同理每一列只有第二行是 # \# # 的也都可以放到一起,形如:

......
######

而这两种情况同时出现的情况下,我们只需要存在某一列两行都是 # \# #,我们就可以把他们拼接成如下形式:

#######......
......#######

这样就成功将所有 # \# # 放到了同一个联通块中。

代码:

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int maxn=1005;
char s[2][maxn];
int cnt[4];
int main(){
   
   
    scanf("%s%s",s[0],s[1]);
    int len=(int)strlen(s[0]);
    for(int i=0;i<len;i++){
   
   
        if(s[0][i]=='#'&&s[1][i]=='.') cnt[0]++;
        else if(s[0][i]=='#'&&s[1][i]=='#') cnt[1]++;
        else if(s[0][i]=='.'&&s[1][i]=='#') cnt[2]++;
        else if(s[0][i]=='.'&&s[1][i]=='.') cnt[3]++;
    }
    if(cnt[0]&&cnt[2]&&!cnt[1]) printf("NO\n");
    else{
   
   
        printf("YES\n");
        for(int j=0;j<cnt[0];j++) printf("#");
        for(int j=0;j<cnt[1];j++) printf("#");
        for(int j=0;j<cnt[2];j++) printf(".");
        for(int j=0;j<cnt[3];j++) printf(".");
        printf("\n");
        for(int j=0;j<cnt[0];j++) printf(".");
        for(int j=0;j<cnt[1];j++) printf("#");
        for(int j=0;j<cnt[2];j++) printf("#");
        for(int j=0;j<cnt[3];j++) printf(".");
        printf("\n");
    }
    return 0;
}

C. Jumps on a Circle

题意:

p p p 个点 0 0 0 p − 1 p-1 p1 围成一圈(即对于 1 < i < n 1 < i < n 1<i<n i i i 的左边为 i − 1 i-1 i1 i i i 的右边为 i + 1 i+1 i+1 1 1 1 的左边为 n n n n n n 的右边为 1 1 1),一个人初始站在 0 0 0,第一次跳 1 1 1 步,第二次跳 2 2 2 步,第 i i i 次跳 i i i 步,共跳 n n n 次,问总共有多少个点被跳到过(包括初始站过的点 0 0 0)。

题解:

数据给出的 n n n 大到 1 0 18 10^{18} 1018,当然我们不能全部跳完,所以我们思考会不会在某个地方出现循环节。而这种情况下的循环节要求到达同一个地方之后的所有行动都要一致。找规律可以发现当 p p p 为奇数时,跳跃 p p p 次即可找到循环节,思考原因我们可以发现,跳跃 p p p 次我们总共跳跃的步数是 ( 1 + p ) ∗ p 2 \frac{(1+p)*p}{2} 2(1+p)p ,其中 1 + p 1+p 1+p 为偶数,即 ( 1 + p ) % 2 = 0 (1+p)\%2=0 (1+p)%2=0,则 ( 1 + p ) ∗ p 2 % p = 0 \frac{(1+p)*p}{2}\%p=0 2(1+p)p%p=0 成立,且下一次跳跃的步数为

### Shohag Loves Greatest Common Divisor (GCD) In both programming and mathematics contexts, the concept of the greatest common divisor (GCD) plays a crucial role. The GCD is defined as the largest positive integer that divides each of the integers without leaving a remainder. #### Mathematical Definition Mathematically speaking, given two non-zero integers \(a\) and \(b\), their greatest common divisor can be denoted by \(\gcd(a, b)\). This value represents the highest number which evenly divides both numbers[^1]. #### Recursive Implementation in C Language A recursive approach to computing the GCD involves repeatedly applying Euclid's algorithm until reaching a base case where one parameter becomes zero: ```c int gcd(int m, int n) { if (n == 0) return m; else return gcd(n, m % n); } ``` This implementation efficiently reduces the problem size at every step through modulo operations while ensuring correctness via recursion. An alternative version ensures larger values are always passed first before performing division checks: ```c int gcd(int n, int m) { int temp; if (n < m) { // Ensure n >= m temp = n; n = m; m = temp; } if (n % m == 0) return m; else return gcd(m, n % m); } ``` Such adjustments improve performance when dealing with specific input ranges but maintain fundamental logic based on modular arithmetic principles[^2]. #### Application Example: String Division Problem An interesting application appears within LeetCode challenge **1071**, concerning strings rather than numeric types directly. Here, determining whether string `s` consists entirely of repeated instances of another substring `t`, effectively translates into checking divisibility properties between lengths |s| and |t|. If such conditions hold true, then further analysis applies similar concepts seen earlier regarding numerical factors and multiples[^3]: Given this background information about how GCD operates across different domains—from basic mathematical theory down to practical coding exercises—one gains deeper insight into its versatile utility beyond mere factorization tasks alone.
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值