ICPC Pacific Northwest Regional Contest 2017题解报告

本文提供了2017年ICPC Pacific Northwest Regional竞赛中多个问题的解题报告,包括题目的简介、解题思路和代码实现。涉及的问题包括奇数回文串判断、因数和求和、物理问题模拟、装修费用优化、拉丁方格填充、数值二分求解、颜色字符差异计数和骰子期望调整等。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

A. Odd Palindrome

在这里插入图片描述

题意 : 回文子串长度为奇数 输出Odd 否则 输出Ornot
思路 : 实际上若字符串长度为奇数输出Odd 偶数出Or not
代码:

#include<bits/stdc++.h>
using namespace std;

int main(){
    string s;
    while(cin >>s){
        if(s.size() % 2 != 0)
            cout <<"Odd." <<endl;
        else
            cout <<"Or not." <<endl;
    }
}

C. Fear Factoring

在这里插入图片描述
题意 : 输入数字a, b。求出a, b之间数字因数和 的 和
思路:分块除法 注意此题卡ull
代码1:

#define ull unsigned long long
using namespace std;
ull f(ull n)
{
    ull ans=0;
    ull left,right;
    for(left = 1; left <= n; left = right + 1){
        right = n / (n / left);
        ans += (n / left) * (left + right) * (right-left+1)/2;
        //这里用的是等差数列 left是首项,right是末项
    }
    return ans;
}
int main(){
    ull a,b;
    while(~scanf("%llu%llu", &a, &b))
    printf("%llu\n", f(b)-f(a-1));
    return 0;

代码2

#include <iostream>
#include <cstdio>
#include <cmath>
#include <cstring>
#include <algorithm>
#define Maxn 1000005
#define LL unsigned long long
using namespace std;

 LL calc(LL n) {
     LL Ans = 0;
     for(LL l=1; l<=n; l++) {
         LL t = n / l;
         LL r = n / t;
         Ans += (l + r) * (r - l + 1) / 2 * t;
         l = r;
     }
     return Ans;
}

int main() {

    LL a,b,Ans = 0;
    while(scanf("%lld %lld",&a,&b) != EOF) {

		cout << calc(b) - calc(a - 1) << endl;
    }

    return 0;
}

E. Straight Shot

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

题意 : 一道物理题,机器人从左边飞到右边 过人行道时有竖直分量的速度影响机器人,给定飞行的方向,使机器人可以飞到右边,求飞到右边的时间
思路:水平与竖直列出啊方程 注意sidewalk的速度是加到Vr上的
在这里插入图片描述

代码 :

#include <bits/stdc++.h>
using namespace std;

// 速度分解 先求时间 再检验
// 输出了 nan ???
double n, x, v; 
double ll, rr, vv, k=0;

int main()
{
    scanf("%lf%lf%lf", &n, &x, &v);
    for(int i=0; i<n; i++){
        scanf("%lf%lf%lf", &ll, &rr, &vv);
        k+=vv*(ll-rr);
    }
    double vy=k/x;
    if(fabs(vy)>v) cout<<"Too hard"<<endl;
    else{
        double vx=sqrt(v*v-vy*vy);
        double t=x/vx, flag=2*x/v;
        if(t>flag) cout<<"Too hard"<<endl;
        else printf("%.3lf\n", t);
    }

    //system("pause");

    return 0;
}

L. Delayed Work

在这里插入图片描述
在这里插入图片描述
题意 : 装修房子 一个工人X元(与工作天数无关) 每天额外交P元,已知一个工人要干K天 ,M个工人则要干K/M天 给K, P, X, 求最小花费
思路 : 1将工人数从0到K枚举

#include <bits/stdc++.h>
using namespace std;

int main()
{
    int k, p, x; scanf("%d%d%d", &k, &p, &x);
    // 1个人要k天 每天*p元 每人共x元
    // 天数向上取整 我在放屁
    double ans=x*1.0+k*p*1.0;
    // 枚举人数
    for(int i=1; i<=100000; i++){
        //int t=(k%i==0)?k/i:(k/i+1);
        double m=i*x*1.0+k/(i*1.0)*p;
        ans=min(ans, m);
    }
    printf("%.3lf\n", ans);

    //system("pause");

    return 0;
}

N. Latin Squares

在这里插入图片描述
在这里插入图片描述
题意 : 模拟 给出一个二维数组 两个判断条件:
1:第一行,第一列为1, 2, 3.。。。
2:每一行,每一列没有重复元素
思路 : 直接根据题意模拟即可 用set处理 可以判重
代码:

#include <bits/stdc++.h>
using namespace std;

// 先判断是否Latin 
// 是的话再判断 第一行 第一列 是否递增

int main()
{
    int n, flag=0; scanf("%d", &n);
    set<char> s;
    string a[40];
    for(int i=0; i<n; i++) cin>>a[i];
    // 先判断每一行
    for(int i=0; i<n; i++){
        for(int j=0; j<n; j++) s.insert(a[i][j]);
        if(s.size()!=n) { flag=1; break;}
    }
    // 再判断每一列
    if(flag==0)
        for(int j=0; j<n; j++){
            for(int i=0; i<n; i++) s.insert(a[i][j]);
            if(s.size()!=n) { flag==1; break;}
        }
    if(flag==1) { cout<<"No"<<endl; /*system("pause");*/ return 0;}
    else{  // 是Latin 
        // 判断第一行
        for(int j=0; j<n; j++) s.insert(a[0][j]);
        int j=0;
        for(set<char>::iterator it=s.begin(); it!=s.end(); it++){
            if(*it!=a[0][j]) { flag=-1; break;}
            else j++;
        }
        // 判断第一列
        for(int i=0; i<n; i++) s.insert(a[i][0]);
        int i=0;
        for(set<char>::iterator it=s.begin(); it!=s.end(); it++){
            if(*it!=a[i][0]) { flag=-1; break;}
            else i++;
        }
        if(flag==-1) { cout<<"Not Reduced"<<endl; /*system("pause");*/ return 0;}
        else { cout<<"Reduced"<<endl; /*system("pause");*/ return 0;}
    }
}

O. Halfway

在这里插入图片描述
在这里插入图片描述
题意 : 给一个数n, 1+2+3+ n-1的和 sum, 求从n-1加到n时的值等于sum/2时,相加的值的数目
思路: 数值较大,遍历超时,故二分
代码:

#include<bits/stdc++.h>
using namespace std;
#define LL long long 
int main(){
    LL n; 
    while(~scanf("%d", &n)){
        LL l = 1,r = n;
        LL sum = ((n-1) * n / 2 + 1)/2;
        while(l <= r){
            LL mid = (l+r) / 2;
            LL cnt = 0;
            cnt = (2*n - 1 - mid) * mid/2;
            if(cnt - (n - mid) < sum && cnt >= sum){
                cout << mid << endl;
                break;
            }
            if(cnt < sum)
                l = mid+1;
            else
                r = mid-1;
        }
    }
    return 0;
}

P. Purple Rain

在这里插入图片描述
在这里插入图片描述

题意 : 给出一个只含有R与B的字符串 求R与B数目相差最多的连续字串的数目
思路 : 刚上来一顿暴力 不出意外的TLE了 将R当成1, B当成-1,求最大连续子列和
最大连续子列和:
从头开始相加,若到i和小于0了,则将开始位置设为i,不断更新sum的值
暴力代码:

#include<bits/stdc++.h>
using namespace std;

string s;
int main(){
    cin >> s;
    int sum = 0;
    int len = s.size();
    int a[len];
    for(int i = 0; i < len; i++){
        if(s[i] == 'B')
            a[i] = -1;
        else
            a[i] = 1;
    }
    int st = 0, e = 0;
    int i = 0, j = 0;
    for(i = 0; i < len - 1; i++){
        int su = 0;
        for(j = i; j < len; j++){
            su += a[j];
            if(abs(su) > sum){
                sum = abs(su);
                st = i+1;
                e = j+1;
            }
        }

    }
    cout << st << ' ' << e << endl;
}

时间1999ms
AC代码:

#include <iostream>
#include <cstring>
#include <cstdio>

using namespace std;
#define Maxn 100005
char s[Maxn];
int a[Maxn],n;

void DP(int &begin,int &end,int &sum) {// sum 表示最大子段和
    sum = a[1];
    int temp = a[1],cur = 1;
    begin = end = 1;
    for(int i=2; i<=n; i++){
        if(temp + a[i] < a[i]){
            temp = a[i];
            cur = i;
        }
        else {
            temp += a[i];
        }
        if(sum < temp){
            sum = temp;
            begin = cur;
            end = i;
        }
    }
}

int main() {
    scanf("%s",s + 1);
    n = strlen(s + 1);
    for(int i=1; i<=n; i++)
        if(s[i] == 'R') a[i] = 1;
        else a[i] = -1;
    int begin1,end1,sum1 = 0;
    DP(begin1,end1,sum1);

    for(int i=1; i<=n; i++)
        if(s[i] == 'R') a[i] = -1;
        else a[i] = 1;

    int begin2,end2,sum2 = 0;
    DP(begin2,end2,sum2);

    if(sum1 < sum2) { printf("%d %d\n",begin2,end2); }
    else if(sum1 > sum2) { printf("%d %d\n",begin1,end1); }
    else {// sum1 == sum2 的时候
        if(begin1 < begin2) printf("%d %d\n",begin1,end1);
        else if(begin1 == begin2) printf("%d %d\n",begin1,min(end1,end2));
        else printf("%d %d\n",begin2,end2);
    }
    return 0;
}

Q. Unloaded Die

在这里插入图片描述
在这里插入图片描述
题意 : 给一个筛子,六个面1, 2, 3, 4, 5, 6,输入每个面的概率
求更改某个数使期望等于3.5 同时使数据变化尽可能小
思路 : 直接算 改概率最大的那个数数据变化最小
代码:

#include<bits/stdc++.h>
using namespace std;
int main(){
    double a[7], ans = 0;
    for(int i = 1; i < 7; i++){
    	cin >> a[i];
    	ans += a[i] * i;
    }
    sort(a+1, a+7);
    printf("%.3f",fabs(ans-3.5) / a[6]);
    return 0;
}

R. Star Arrangements

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值