• 2019牛客国庆集训派对day1


    2019牛客国庆集训派对day1

    // 2019.10.1 国庆练习赛
    // 比赛链接:2019牛客国庆集训派对day1
    // 虽然我国庆七天溜回家了,队友还是督促我好好打比赛...

    // 毕竟现场赛也没几天了,好好练习哈

    A 全 1 子矩阵

    题目大意

    判断矩阵是否存在子矩阵满足 (x_1 le x le x_2, y_1 le y le y_2) 内全是1,其他地方为0。

    水题,暴力判断一下即可。

    AC代码

    #include<iostream>
    #include<cstdio>
    using namespace std;
    
    char mat[15][15];
    int n, m;
    int x1, y1, x2, y2;
    
    void check() {
        for(int i=x1;i<=x2;i++) {
            for(int j=y1;j<=y2;j++) {
                if(mat[i][j]=='1') {
                    mat[i][j] = '0';
                }else {
                    printf("No
    ");
                    return;
                }
            }
        }
        
        for(int i=0;i<n;i++) {
            for(int j=0;j<m;j++) {
                if(mat[i][j]=='1') {
                    printf("No
    ");
                    return;
                }
            }
        }
        printf("Yes
    ");
        
    }
    
    int main() {
        while(scanf("%d %d", &n, &m)!=EOF) {
            for(int i=0;i<n;i++)
                scanf("%s", mat[i]);
            
            x1 = y1 = x2 = y2 = -1;
            for(int i=0;i<n&&x1==-1;i++) {
                for(int j=0;j<m;j++) {
                    if(mat[i][j]=='1') {
                        x1 = i, y1 = j;
                        break;
                    }
                }
            }
            
            for(int i=n-1;i>=0&&x2==-1;i--) {
                for(int j=m-1;j>=0;j--) {
                    if(mat[i][j]=='1') {
                        x2 = i, y2 = j;
                        break;
                    }
                }
            }
            
            if(x1==-1||x2==-1) {
                printf("No
    ");
                continue;
            }
            
            check();
        }
        return 0;
    }
    

    B 组合数

    题目大意

    给定n 与 k, 求 (min(C_n^k, 10^{18}))

    (0 ≤ k ≤ n≤10^9) , 至多 (10^5) 组数据。

    思路

    组合数 (C_{100}^{50}) 已经远超 (10^{18}),那么显然可以考虑使用 O(n) 的递推式求组合数,即便 (10^5) 组数据也跑的过去。

    再次复习一遍组合数递推式

    [C_n^k = frac {n-k+1} {k} C_n^{k-1} ]

    AC代码

    折腾半天才A,注意到 (C_n^{n-k} = C_n^k) , 先 k = min(k, n-k),保证计算过程是单调的。

    double A不过去,又要用到无敌的 __int128 。赛后发现可以用 long double 保证精度。

    #include<cstdio>
    using namespace std;
    typedef long long ll;
    //typedef __int128 i128;
    const ll INF = 1e18;
    
    ll cal(ll n, ll k) {
        if(k>n/2) k = n - k;
        // i128 res = 1;
        long double res = 1.0;
        for(ll i=1;i<=k;i++) {
            res = res*(n-i+1)/i;
            if(res>INF) return INF; 
        }
        return (ll)res;
    }
    
    int main() {
        ll n, k;
        while(scanf("%lld %lld", &n, &k)!=EOF) {
            printf("%lld
    ", cal(n, k));
        }
        return 0;
    }
    

    优雅简洁的Python写法:

    while True:
        try:
            n, k = map(int, input().split())
            k = min(k, n-k)
            
            ans = 1
            for i in range(1, k+1):
                ans = ans * (n-i+1) // i
                if ans>10**18 :
                    ans = 10**18
                    break	
            print(ans)
        except EOFError:
            break
    

    E Numbers

    题目大意

    有 n 个范围在 [0, 99] 之间的整数,现在他们相连写成了一列数,问原来的数组有多少种可能。

    思路

    原以为是 dp,写了一半不对劲,改写 dfs ,没搜出样例,溜了。。。

    // 原来是dfs时 pos==len 才++ans。

    AC代码

    #include<cstdio>
    #include<iostream>
    #include<cstring> 
    using namespace std;
     
    char s[55];
    bool vis[100];
    int len;
    int ans;
     
    void dfs(int pos) {
        if(pos>len) return;
        if(pos==len) {
            ++ans;
            return;
        }
        int n = s[pos]-'0';
        int nn = n*10;
        if(!vis[n]) {
            vis[n] = 1;
            dfs(pos+1);
            vis[n] = 0;
        }
        if(nn && pos<len-1) nn += s[pos+1]-'0';
        if(nn>=10 && !vis[nn]) {
            vis[nn] = 1;
            dfs(pos+2);
            vis[nn] = 0;
        }
    }
     
    int main() {
        while(scanf("%s", s)!=EOF) {
            memset(vis, 0, sizeof(vis));
            len = strlen(s);
            ans = 0;
            dfs(0);
            printf("%d
    ", ans);
        }
        return 0;
    }
    

    F 4 Buttons

    题目大意

    Bobo一开始位于平面上的原点 (0,0),有四种操作:向右最多移动a步,向上最多移动b步,向左最多移动c步,向下最多移动d步。问执行 n 次操作可以到达多少个不同的点。

    思路

    只进行一步的操作很简单,分别可以到达坐标轴上离原点最远的 (a, 0), (0, b), (-c, 0), (0, -d)。故包含原点在内共有 1 + a + b + c + d 个点。

    多步的话,我们先只看第一象限内的情况:

    第一次操作到达x轴上区间 [1, a],第2次到第n次竖直方向上能到达 [1, (n-1)b)] ,共 a*(n-1)b个点;

    两次操作到达x轴上区间 [a+1, 2a], 第2次到第n次竖直方向上能到达 [1, (n-2)b)] ,共 a*(n-2)b个点;

    ···

    n-1次操作到达x轴上区间 [(n-2)a+1, (n-1)a], 第n-1次到第n次竖直方向上能到达 [1, b] ,共 a*b个//点;

    // n 次操作到达x轴上最远的a个点 [(n-1)a+1, na]。

    所以答案很简单, 1 + n(a + b + c + d) + n(n-1)/2 * (ab + bc + cd + ad) 。

    AC代码

    #include<cstdio>
    using namespace std;
    const int mod = 1e9+7;
    typedef long long ll;
    ll n, a, b, c, d;
    int main() {
        while(scanf("%lld %lld %lld %lld %lld", &n, &a, &b, &c, &d)!=EOF) {
            ll ans = 1 + (a+b+c+d)%mod * n%mod + n*(n-1)/2 %mod
            *((a*b%mod+ b*c%mod + c*d%mod + a*d%mod)%mod)%mod;
            printf("%lld
    ", ans%mod);
        }
        return 0;
    }
    

    H 有向图

    题目大意

    数学题,待补,我的锅。

  • 相关阅读:
    在庫購買管理(MM)
    指図ステータス
    購買発注変更、照会画面に初期表示される発注伝票はどのように決まっているのか
    金額処理
    翻訳
    mysql 与mongodb的特点与优劣
    PHP经典算法
    Linux下PHP安装redis扩展
    Linux上安装Redis教程
    PHP插入法排序
  • 原文地址:https://www.cnblogs.com/izcat/p/11618652.html
Copyright © 2020-2023  润新知