• 哈尔滨工程大学ACM预热赛(A,C,H,I)


    A:

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

    时间限制:C/C++ 1秒,其他语言2秒
    空间限制:C/C++ 32768K,其他语言65536K
    64bit IO Format: %lld

    题目描述

    小虎刚刚上了幼儿园,老师让他做一个家庭作业:首先画3个格子,第二行有2个格子,第三行有1个格子。每行的格子从左到右可以放棋子,但要求除第一行外,每行放的棋子数不能超过上一行的棋子。玩了一会儿,小虎问大哥大虎:这个作业有很多种摆放法,我想都找到,但我不知道有多少中方案,你能帮助我么?
    大虎是学校信息学集训队的,立刻想到用计算机来解决这个问题,并很快有了解答:13。第二天他把问题拿到了学校,并说如果第一行有N个格子,第二行有N-1个格子,…,第N行有1个格子,怎么办?现在请你一块来帮助他解决这个难题。
    数据范围
    30%数据:1≤N≤12
    50%数据:1≤N≤30
    100%数据:1≤N≤100

    输入描述:

    仅一行,一个正整数N。

    输出描述:

    一行,方案总数。
    示例1

    输入

    复制
    2

    输出

    复制
    4

    说明

    样例1说明N=2时,有如下4中摆放棋子法(*表示棋子,_表示空格):
    方案法 1 2 3 4
    摆放法 *_ ** *_ **
    摆放法 _ _ * *
    示例2

    输入

    3

    输出

    13


    思路:看到这种小规模题,先打表。
    打表代码:大力搜
    LL sum = 0;
    int n = 6;// 改变n 
    void dfs(int now,int dep){
        if(dep == 1){
            now==0?sum+=1:sum+=2;
            return;
        }
        for(int i = 0 ; i <= now && i <= dep; i++){
            dfs(i,dep-1);
        }
    }
    int main()
    {
        for(int i = 1 ; i <= n ; i ++){
            dfs(i,n-1);
        }
        printf("%lld
    ",sum);
    }

    然后发现,4,13,41,131,428。。。。卡特兰数减去一。

    再看了看数据很大又没有取模。直接Py写了组合数。

    卡特兰数 H[n] = c(2*n,n)/(n+1);

    代码:

    
    
    comb = [[0 for i in range(212)] for i in range(212)]
    for i in range(0,210):
        comb[i][0] = comb[i][i] = 1;
        for j in range(1,i):
            comb[i][j] = comb[i-1][j] + comb[i-1][j-1];
    n = int(input());
    n+=1;
    print(comb[2*n][n]//(n+1) - 1);


    C题:
    链接:https://ac.nowcoder.com/acm/contest/554/C
    来源:牛客网
    时间限制:C/C++ 1秒,其他语言2秒
    空间限制:C/C++ 32768K,其他语言65536K
    64bit IO Format: %lld
    
    

    题目描述

    
    
    国王有一块神奇土地
    第一天可以产a吨粮食,第二天会变成前一天的a倍,以此类推。
    n天后大臣准备把这些粮食尽可能多的平均分给b个城池
    为了方便,每个城池分到的粮食都是整吨整吨哒!
    剩下的粮食国王准备贪污
    国王能贪到多少吨粮食呢?

    输入描述:

    输入的第一行为一个数字T(T<=100),表示数据输入的组数。
    之后每行3个数字,分别表示 a, n, b(1<=a,n<= 1000,000,000;1<=b<=1000 )。

    输出描述:

    对于每组数据输出对应结果
    示例1

    输入

    1
    2 2 3

    输出

    1
    快速幂取模。a^n % b;
    不贴代码了


    H:
    链接:https://ac.nowcoder.com/acm/contest/554/H
    来源:牛客网
    时间限制:C/C++ 1秒,其他语言2秒
    空间限制:C/C++ 262144K,其他语言524288K
    64bit IO Format: %lld

    题目描述

    杨主席这段时间由于要找实习,所以非常焦躁。因为公司的面试都非常的难,杨主席不知道从哪入手。于是他就找了他的学长坑坑询问情况,坑坑告诉他要注重算法的学习,于是就给杨主席出了一个题目看看他算法学的怎么样,这道题是这样的:有N个人排成一排,从1到N按顺序依次编号,现在要执行N次操作,第一次操作让所有的人都蹲下,之后第二次操作让编号是2和2的倍数的人全部站起来,然后第三次操作让编号是3和3的倍数的人全部做相反的动作(站着的人蹲下,蹲下的人站起来),以此类推...,最后第N此操作让编号为N的这个人也做相反的动作。请问N次操作后,从第A个人到第B个人之间(包括A和B这两个数字,且A<B)有多少人是站着的?

    输入描述:

    输入数据为T组数据(1<=T<=10)。
    每组数据输入包含三个数字N,A,B(1<=N<=1000000,1<=A<B<=N)。

    输出描述:

    对于每组数据,输出一个整数,表示从第A个人到第B个人之间有多少人站着。
    示例1

    输入

    1
    5 1 3

    输出

    2
    思路:又是打表找规律题。首先确定一个位置pos,改变的次数是pos的因子数减1 次。(假设首先是蹲着)
       打表:
       
    int a[1001];
    memset(a,0,sizeof(a));
    int op = 1000;
    for(int i = 2 ; i <= op ; i++ ){
        for(int j = 2 ; j <= i ; j++){
            if(i%j == 0){
                a[i] ^= 1;
            }
        }
    }
    for(int i = 1 ; i <= op ; i++){
        printf("%d ",a[i]);
        if(!a[i])puts("");
    }puts("");

    很容易发现1的个数会每次+2。

    求个前缀和就行了。

    代码:

    #include<bits/stdc++.h> 
    using namespace std;
    #define LL long long
    #define INF 2000000000
    const LL mod = 1e9+7;
    int a[2000100];
    int main()
    {
        memset(a,0,sizeof(a));
        int p = 0,k = 0;
        while(k <= 1000001){
            a[k++] = 0;
            for(int i = 0 ; i < 2*p && k <= 1000001; i++){
                a[k++] = 1;
            }
            p++;
        }
        for(int i = 2 ; i <= 1000000 ; i++){
            a[i] += a[i-1]; 
        }
        int t;scanf("%d",&t);
        while(t--){
            int n,x,y;
            scanf("%d %d %d",&n,&x,&y);
            printf("%d
    ",a[y] - a[x-1]); 
        }
    }
    /*
    2
    9 1 4
    1000000 1 1000000
    */ 

    I:

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

    时间限制:C/C++ 1秒,其他语言2秒
    空间限制:C/C++ 32768K,其他语言65536K
    64bit IO Format: %lld

    题目描述

    坑坑作为一个ACMer,经常要对一组数字进行排序,在排序过程中,将两个数字交换位置的花销是这两个数字的和,慢慢的他想实现一种最低花销的排序方式,你们能帮助他吗?

    输入描述:

    输入包含多组测试数据。
    每组测试输入包含一组数字包含的整数个数n以及n个整数mi(1<=n<1000,0<=mi<=10000)给定的整数互不重复。

    输出描述:

    对于每组测试数据,输出一个整数,给定整数按升序排序时所需花销的最小值。
    示例1

    输入

    4
    3 1 5 4 

    输出

    13


    思路:
    首先肯定交换的肯定是闭环上的数。比如说 4 3 1 2 5。第一个环是4-->2-->3-->1-->4,这几个位置上的数,交换一下位置可以得到递增的。环是以number-->pos[number]-->pos[pos[number]]....下去的。
    比赛的时候爆WA了,说说赛中的想法。
    赛中的时候想法就是肯定是用环中最小的数作为媒介去交换啊,记一个环的元素有k个,最小的数为Min,环的元素和为Sum。
    肯定是拿Min去做n-1次交换啊,所以答案是(Sum-Min)+(k-1)*Min;即用最小的元素去跟其他的k-1个交换产生的价值。
    没考虑到另外一种情况,举个例子:1 400 200 300,这个数组,环是400->300->200->400。那么我们拿200去换吗?肯定不是,显然用1作为媒介交换是最合适的。

    所以有了第二种情况(赛后看了下AC的代码发现的思维误区),即拿数组中最小的元素作为媒介,去把当前环中的数交换成有序的。
    记全部元素中最小的数是All_Min产生的代价是Min+Sum+(k-1)*All_Min。手推一下就OK的。
    所以每次环增加的代价是这两种情况取小的那种。(说实话这题很质量啊,很考验思维。。哎还是我太菜了)

    最后注意的是离散化一下数组,因为题目中给定的不是完全的1~n的数字。
    代码:
    #include<bits/stdc++.h> 
    using namespace std;
    #define LL long long
    #define INF 2000000000
    const LL mod = 1e9+7;
    int mp[10001];
    int main()
    {
        int a[1001],pos[1001],vis[1001];
        int n;
        while(~scanf("%d",&n)){
            memset(mp,0,sizeof(mp));
            vector<int>vec;
            int Min = 100000000;
            for(int i = 1 ; i <= n ; i++){
                scanf("%d",a+i);
                vec.push_back(a[i]);
                Min = min(a[i],Min);
                pos[i] = i;//应该在的位置 
            }
            sort(vec.begin(),vec.end());
            for(int i = 0 ; i < n ; i++){
                mp[vec[i]] = i+1;
            }//离散化 
            LL sum = 0;
            memset(vis,0,sizeof(vis)); 
            for(int i = 1 ; i <= n ; i++){
                if(!vis[i]){
                    if(pos[i] != mp[a[i]]){
                        int be = i;
                        vector<int>v;
                        int nowsum = 0;//存储当前环中元素和 
                        while(!vis[be]){
                            v.push_back(a[be]);
                            vis[be] = 1;
                            nowsum += a[be];
                            be = pos[mp[a[be]]];    
                        }
                        sort(v.begin(),v.end());
                        int useself = (v.size()-2)*v[0]+nowsum;
                        int    use_min_number = v[0] + nowsum + (v.size()+1)*Min;
                        //两种情况取小的那种,加到sums上。 
                        sum += min(useself,use_min_number);
                    }
                    else{
                        vis[i] = 1;
                    }
                }
                
            }
            cout<<sum<<endl;
        } 
    }
    /*
    5
    1 2 3 4 0
    4
    1 300 400 100
    */ 
    
    
    
     
  • 相关阅读:
    javascript权威指南(2)
    javascript权威指南(1)
    java之jvm学习笔记四(安全管理器)
    JavaEE Tutorials (2)
    Java高效编程(2) -- Creating and Destroying Objects
    JavaEE Tutorials (1)
    Java Web整合开发(12) -- JDBC
    memcached安装和验证
    [leetcode]Two Sum
    Java Web整合开发(11)
  • 原文地址:https://www.cnblogs.com/Esquecer/p/10650175.html
Copyright © 2020-2023  润新知