JXNU 2017 校ACM程序设计竞赛(16级)题解

来源:互联网 发布:mac响声很大 编辑:程序博客网 时间:2024/05/29 16:28

比赛重现地址:http://acm.hdu.edu.cn/diy/diy_listproblem.php?cid=32026

1001 幼稚园的游戏
题解:其实就是把字符串中的除字母和数字外的所有字符删掉,把所有字母都转成小写,然后从前和后同时开始遍历。

详细请看代码

#include <iostream>#include <string>using namespace std;int main() {    cin.sync_with_stdio(false);    string c;    string str;    while (getline(cin, c)) {        str = "";        for (int i = 0; i<c.length(); i++) {            if ((c[i] >= '0'&&c[i] <= '9') || (c[i] >= 'A'&&c[i] <= 'Z') || (c[i] >= 'a'&&c[i] <= 'z')) {                if (c[i] >= 'A'&&c[i] <= 'Z') {                    c[i] = c[i] - 'A' + 'a';                }                str += c[i];            }        }        int flag = 0;        int l = 0, r = str.length() - 1;        while (l<r) {            if (str[l] != str[r]) {                flag = 1;                break;            }            l++;            r--;        }        if (flag) {            cout << "false" << endl;        }        else {            cout << "true" << endl;        }    }    return 0;}

1002 小学生的游戏
题解:这道题是卡了朴素的解法的,所有你要想都一些技巧,因为说了一定要是连续的正整数序列,所有如果想要最长肯定是由1开始的,所有可以通过前n项和的公式【(1+n)*n/2】求出最大可以到多少,然后再通过这个来枚举项数来求序列,这样就节省了很多时间了

详细请看代码

#include<iostream>#include<cstdio>using namespace std;double n;int main(){    while(~scanf("%lf",&n)){        int pos = 0;        for(int i = 2; ; i++){            if(((1+i)*i)/2 >n){                pos = i;                break;            }        }        pos--;        int con=0;        for(int i = pos; i > 1; i--){//枚举项数             if(double((n-(i*(i-1))/2)/i)==(int)((n-(i*(i-1))/2)/i)){//如果该项数能够成立就打印输出                 con++;                for(int j = (n-(i*(i-1))/2)/i; j < (n-(i*(i-1))/2)/i+i-1; j++){//首项~末项                     printf("%d ",j);                }                printf("%d\n", (int)(n-(i*(i-1))/2)/i+i-1);            }        }        if(con==0){            printf("NONE\n");        }    }    return 0;}

1003 初中生的游戏
题解:应该都学过求导判断函数是递增还是递减的吧,F(x) 的导数应该是

F’(x)=42*x^6+48*x^5+21*x^2+10*x-y;

你就会发现其实导数在0~100内是递增的,F’(x)在x=0时是最小的,所以可以用二分法去枚举求出F’(x)<0时最大的x的值,那时候这个函数就可以求出最小值了。

详细请看代码

#include <iostream>#include <iomanip>#include <cmath>using namespace std;const double eps = 1e-8;double y;double solve(double x){    return 42*pow(x,6)+48*pow(x,5)+21*x*x+10*x-y;}int main(){    int T;    cin.sync_with_stdio(false);    cin>>T;    while(T--){        cin>>y;        double x=0;        double l=0,r=100;        while(l<=r){            double mid=(l+r)/2;            if(solve(mid)<0){                x=mid;                l=mid+eps;            }            else{                r=mid-eps;            }        }        cout<<fixed<<setprecision(4)<<6*pow(x,7)+8*pow(x,6)+7*pow(x,3)+5*x*x-y*x<<endl;    }    return 0;}

1004 这匹马是不是稀有的金色斑马
题解:这题就是判断两种颜色是不是最多相差1,但是对0要进行特判,因为存在有条纹为0就不是斑马了

详细请看代码

#include <iostream>#include <cstring>#include <string>#include <vector>#include <queue>#include <algorithm>#define N 1000010#define LL long longusing namespace std;int n, m;int main() {    cin.sync_with_stdio(false);    freopen("in.txt","r",stdin);    freopen("out.txt","w",stdout);    while (cin >> n >> m) {        if (n == 0 || m == 0) {            cout << "NO" << endl;            continue;        }        if (abs(n - m) > 1) {            cout << "NO" << endl;        }        else {            cout << "YES" << endl;        }    }    return 0;}

1005 ZZ的机器人
题解:其实只要判断左边向右遍历在遇到第一个向右走或者不动的的机器人把这个位置记为l,再从右边向左遍历在遇到第一个向左走或者不动的的机器人把这个位置记为r,l~r的范围内有多少个能动的机器人,这样就代表了多少次题意上的碰撞(PS:在这个范围内肯定是全部为碰撞坏掉的,因为他们走不出去了)

详细请看代码

#include <iostream>#include <cstring>#include <string>using namespace std;int main() {    cin.sync_with_stdio(false);    int T;    int l, r;    string str;    cin >> T;    while (T--) {        cin >> str;        int len = str.length();        for (l = 0; l < len; l++) {            if (str[l] != 'l') {                break;            }        }        for (r = len - 1; r >= 0; r--) {            if (str[r] != 'r') {                break;            }        }        int ans = 0;        for (; l <= r; l++) {            if (str[l] != 'd') {                ans++;            }        }        cout << ans << endl;    }    return 0;}

1006 这是一道有味道的题目
题解:因为一定要同时回到原来的位置,并且要翻面,所以每个烤串要经过所有位置,因为要保证翻面,所以先把全部位置是否翻面求出来,如果全部加起来是偶数就说明不能翻面,所以要改一个数,使得他能在最后是翻面的。再去看它是不是全部经过了一遍,这个就是看他是否只有一个环。如果不止一个环,所以就要不断的删环改边使得它最后只剩一个环,就能满足情况了,看是否成环就直接用dfs就能求出来。
因为这题是cf上的一道题目,我好早之前写的,觉得特别有趣,所以就放上来了,开始中文题目是我看代码写出来的,所以有点问题,因为测题人员的疏忽,题目意思已经完全错了,真正的题目意思是说每个烤串都要经过每个炉子烤正反面
题解:因为每个烤串都要经过每个炉子烤正反面,所以可以简化为一定要同时回到原来的位置,并且要翻面,(因为再来一次就是每个烤串都要经过每个炉子烤正反面),所以每个烤串要经过所有位置,因为要保证翻面,所以先把全部位置是否翻面求出来,如果全部加起来是偶数就说明不能翻面,所以要改一个数,使得他能在最后是翻面的。再去看它是不是全部经过了一遍,这个就是看他是否只有一个环。如果不止一个环,所以就要不断的删环改边使得它最后只剩一个环,就能满足情况了,看是否成环就直接用dfs就能求出来。

详细请看代码

#include <iostream>#include <cstring>#include <string>#include <vector>#include <queue>#include <algorithm>#define N 200010#define LL long longusing namespace std;int n;bool vis[N];int p[N], b[N];void dfs(int num) {    vis[num] = true;    if (!vis[p[num]]) {        dfs(p[num]);    }}int main() {    int ans, cnt;    cin.sync_with_stdio(false);    while (cin >> n) {        memset(vis, false, sizeof(vis));        ans = 0;        cnt = 0;        for (int i = 1; i <= n; i++) {            cin >> p[i];        }        for (int i = 1; i <= n; i++) {            cin >> b[i];            if (b[i] == 1) {                cnt++;            }        }        if (!(cnt % 2)) {            cnt = 1;        }        else {            cnt = 0;        }        for (int i = 1; i <= n; i++) {            if (!vis[i]) {                dfs(i);                ans++;            }        }        if (ans == 1) {            ans = 0;        }        cout << ans + cnt << endl;    }    return 0;}

1007 小明的电梯
题解:把情况给分析好来,情况如下:

1、如果要去的楼层都在当前楼层下面,就无论现在方向如何都要向下
2、如果要去的楼层都在当前楼层上面,就无论现在方向如何都要向上
3、正常情况

其实对于各种情况有各自的处理(都先按楼层号从下到大排好序)

1、直接当前楼层号减去最小的楼层号就好了
2、直接最大的楼层号减去当前楼层号就好了
3、(1)当前方向是向上,先最大的楼层号减去当前楼层号,再加上最大的楼层号减去最小的楼层号
3、(2)当前方向是向下,先当前楼层号减去最小的楼层号,再加上最大的楼层号减去最小的楼层号

详细请看代码

#include <iostream>#include <string>#include <algorithm>#define N 10010using namespace std;int main() {    cin.sync_with_stdio(false);    int T;    int sum;    int num[N];    int flag, m, n;    cin >> T;    while (T--) {        cin >> m >> flag;        cin >> n;        for (int i = 0; i < n; i++) {            cin >> num[i];        }        sort(num, num + n);        if (m >= num[n - 1]) {            sum = m - num[0];        }        else if (m <= num[0]) {            sum = num[n - 1] - m;        }        else {            if (flag == 1) {                sum = (num[n - 1] - m) + (num[n - 1] - num[0]);            }            else {                sum=(m-num[0]) + (num[n - 1] - num[0]);            }        }        cout << sum << endl;    }    return 0;}

1008 女装大佬的高难度进制转换
题解:对字符串判断一下把字符串真正的内容和括号里面的内容分割开来,看他当前是几进制,然后就是正常的进制转换了(要把字母转化为数字来求)

详细请看代码

#include <iostream>#include <string>#define LL long longusing namespace std;int main(){    cin.sync_with_stdio(false);    string str;    LL num,sum;    while(cin>>str){        sum=0;        num=0;        for(int i=str.length()-2;i>=0;i--){            if(str[i]=='('){                for(i=i+1;i<str.length()-1;i++){                    num=num*10+str[i]-'0';                }                break;            }        }        for(int i=0;i<str.length()-1;i++){            if(str[i]=='('){                break;            }            if(str[i]>='0'&&str[i]<='9'){                sum=sum*num+str[i]-'0';            }            else{                sum=sum*num+str[i]-'A'+10;            }        }        cout<<sum<<endl;    }    return 0;}

总结:总之这次比赛题目还是有点难度的比较考思维,对于代码能力要求不是特别高(为了防止出现懂这种算法就能AC的情况,我们废了一题,对某位出题人说声对不起(。・_・。)ノ),希望大家加油↖(^ω^)↗

阅读全文
0 0
原创粉丝点击