Codeforces Round #663 (Div. 2)

A. Suborrays

直接从小到大或从大到小输出即可。

#include<bits/stdc++.h>
using namespace std;
int t, n;

int main(){
    scanf("%d", &t);
    while(t--){
        scanf("%d", &n);
        for(int i=n; i>0; i--) printf("%d ", i);
        printf("\n");
    }
    return 0;
}




B. Fix You

除第n行和第m列格子外,其余格子中的物品最终都会被运输到第n行或第m列的格子中,所以只要保证第n行的格子中的物品能一直向右运输,第m列格子的物品能一直向下运输,就可以保证所有物品最终被运输到(n, m)格子。

#include<bits/stdc++.h>
using namespace std;
const int MAX = 100+5;
char a[MAX][MAX];
int t, n, m, ans;

int main(){
    scanf("%d", &t);
    while(t--){
        ans = 0;

        scanf("%d%d", &n, &m);
        for(int i=1; i<=n; i++){
            scanf("%s", a[i]+1);
        }

        for(int i=1; i<n; i++){
            if(a[i][m]=='R') ans++;
        }

        for(int i=1; i<m; i++){
            if(a[n][i]=='D') ans++;
        }

        printf("%d\n", ans);
    }
    return 0;
}




C. Cyclic Permutations

对于序列中的任意一个数,如果它的两侧均有大于a的元素,那么必然会形成环。反之,如果将比元素a大的数全部安排在同一侧,就不会出现环。因为元素a序列中任意一个元素,所以要保证“比元素a大的数全部在同一侧”,就需要将除n以外(因为没有比n还大的元素)的(n-1)个数从小到大放置在元素n的两侧,并且每次放置只能放置在序列的两端的位置上(这样才能保证比a大的数在同一侧),这样一共有2(n-1) 种序列,这是不出现环的序列个数,总的序列个数为n!,那么有环的序列就是n!-2(n-1)种。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int mod = 1e9+7;
int n;
ll ans;

ll pow(int n){
    ll tmp;
    if(n==1) return 2;
    tmp = pow(n/2)%mod;
    if(n%2==0) return (tmp*tmp)%mod;
    else return (tmp*tmp*2)%mod;
}

int main(){
    scanf("%d", &n);
    ans = 1;
    for(int i=2; i<=n; i++){
        ans = (i*ans)%mod;
    }
    printf("%lld", (ans+mod-pow(n-1))%mod);
    return 0;
}




D. 505

  • 因为m≥n,当n≥4时,必定存在四个2 * 2的矩阵可以组成一个4 * 4的矩阵,如果2 * 2的矩阵满足条件,那么很显然4 * 4的矩阵一定是不满足条件的。所以n≥4时无解。
  • 当n=1时,不存在偶数阶的矩阵,默认是good,答案就是0。
  • 当n=2或n=3时,通过枚举第一列的状态,并通过第一列的状态构造符合条件的矩阵,在构造中获得每一种状态下修改的次数,取最小值即可。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int MAX = 1e6+5;
int two[4][2]={{0,0}, {0,1}, {1,0}, {1,1}};  //n==2时,第一列的四种状态
int thr[8][3]={{0,0,0}, {0,0,1}, {0,1,0}, {0,1,1}, {1,0,0}, {1,0,1}, {1,1,0}, {1,1,1}};  //n==3时,第一列的8种状态
int n, m, ans;
int a[5][MAX], t[5][MAX];
char tmp[MAX];

int main(){
    scanf("%d%d", &n, &m);
    if(n>=4){  //n>=4,无解
        ans = -1;
        for(int i=0; i<n; i++) scanf("%s", tmp);
    }
    else{
        for(int i=0; i<n; i++){
            scanf("%s", tmp);
            for(int j=0; j<m; j++){
                a[i][j] = tmp[j]-'0';
            }
        }
        if(n==1) ans = 0;  //n==1, good, ans=0
        else{
            if(n==2){  /n==2
                ans = 1e9;
                for(int i=0; i<4; i++){  //枚举四种状态
                    int cnt = 0;
                    
                    t[0][0] = two[i][0];
                    t[1][0] = two[i][1];  //初始化第一列的状态
                    
                    if(t[0][0]!=a[0][0]) cnt++;
                    if(t[1][0]!=a[1][0]) cnt++;  //计数修改的次数

                    for(int j=1; j<m; j++){  //根据第一列的状态构建合法矩阵
                        t[0][j] = a[0][j];
                        t[1][j] = a[1][j];  //从原序列复制第j列的状态
						//判断当前状态时候合法,合法则不做修改;不合法则进行修改,同时计数
                        int mat = t[0][j] + t[1][j] + t[0][j-1] + t[1][j-1];
                        if(mat%2==0){
                            t[0][j] = (t[0][j]? 0:1);  //因为j-1列已经使j-1列以前的满足条件了,不能再更改,所以只能改j列
                            cnt++;
                        }
                    }

                    ans = min(ans, cnt);
                }
            }
            else{
                ans = 1e9;
                for(int i=0; i<8; i++){
                    int cnt = 0;
                    t[0][0] = thr[i][0];
                    t[1][0] = thr[i][1];
                    t[2][0] = thr[i][2];
                    if(t[0][0]!=a[0][0]) cnt++;
                    if(t[1][0]!=a[1][0]) cnt++;
                    if(t[2][0]!=a[2][0]) cnt++;

                    for(int j=1; j<m; j++){
                        t[0][j] = a[0][j];
                        t[1][j] = a[1][j];
                        t[2][j] = a[2][j];

                        int matu = t[0][j] + t[1][j] + t[0][j-1] + t[1][j-1];
                        int matd = t[1][j] + t[2][j] + t[1][j-1] + t[2][j-1];

                        if(matu%2 && matd%2) continue; //上下两个子矩阵均合法
                        if(matd%2){  //上面矩阵不合法,修改[0][j]
                            t[0][j] = (t[0][j]? 0:1);
                            cnt++;
                        }
                        else if(matu%2){  //下面矩阵不合法,修改[2][j]
                            t[2][j] = (t[2][j]? 0:1);
                            cnt++;
                        }
                        else{ //两个矩阵都不合法,修改两个矩阵的交点[1][j]
                            t[1][j] = (t[1][j]? 0:1);
                            cnt++;
                        }
                    }
                    ans = min(ans, cnt);
                }
            }
        }
    }
    printf("%d", ans);
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值