安徽省2019年程序设计大赛 L.曲奇工厂 H.不要回文 K.福报

A.机器人足球
时间限制:2s
描述:
足球场地长为100,宽为20,对方球门的坐标为(100,10),你要控制一个机器人踢球,初始位置为(x,y),机器人可以朝任何方向移动,但不能超出场地边界。当机器人与球门距离不超过10时,可以射门。问机器人从初始位置出发到射门,最少要移动多少距离?(四舍五入到小数点后3位)

输入
每组输入为2个整数,分别为x,y
0<=x<=100
0<=y<=20

输出
输入最小移动的距离
 

机器人足球 简单几何,注意到距离d<=10的时候移动距离为0

 

#include 

using namespace std;


typedef long long LL;

template
void OOM(T a, string s = "") {
    cerr << s << ":\t";
    for (auto e:a) {
        cerr << e.first << "," << e.second << " ";
    }
    cerr << endl;
}

template
void OO(T a, string s = "") {
    cerr << s << ":\t";
    for (auto e:a) {
        cerr << e << " ";
    }
    cerr << endl;
}

template
inline void oo(string str, T val) { cerr << str << val << endl; }

template
inline T read() {
    T x;
    cin >> x;
    return x;
}

#define endl '\n'
#define FOR(i, x, y) for (decay::type i = (x), _##i = (y); i < _##i; ++i)
#define FORD(i, x, y) for (decay::type i = (x), _##i = (y); i > _##i; --i)


int main() {
    std::iostream::sync_with_stdio(false);
    cin.tie(nullptr);
    cout.tie(nullptr);
    double x(read()), y(read());
    cout << fixed << setprecision(3) << max(hypot(x - 100, y - 10) - 10, 0.0) << endl;

    return 0;
}


B

B.纸牌识别
时间限制:2s
描述:
Alice沉迷于机器人研究,他打算做一个机器人来检查一副扑克是否完成,现在,他想请你帮他写一个程序,来识别纸牌。每张纸牌都有一个花色(四种花色,分别用大写字母P,K,H,T表示)和一个数字点数(1-13).纸牌可以用ABC的形式来表示,A代表花色,BC代表数字,如果数字小于10,会有一位补0.比如花色是P,数字是9的纸牌会表示成P09.一副完整的纸牌有52张牌,四种不同的花色各有1张数字1-13的牌。
你的程序要读入一个字符串,表示缺少的纸牌有哪些,如果包含相同的纸牌(花色数字都相同)输出GRESKA,否则输入每种花色剩余的纸牌数量。

输入
输入只有一行,一个字符串s,s的长度小于等于1000.

输出
如果输入中包含相同的纸牌,输出GRESKA,否则分别输入四个整数,代表P,K,H,T四种花色纸牌的剩余数量。

样例输入1

P01K02H03H04
1
样例输出1

12 12 11 13
1
样例输入2

H02H10P11H02
1
样例输出2

GRESKA
1
提示
样例1中P花色缺少P01,所以只有12张,K花色缺少K02,所以也只有12张,H花色缺少两张;T花色不缺牌。

 

模拟

#include 

using namespace std;

typedef long long LL;
#define endl '\n'
#define FOR(i, x, y) for (decay::type i = (x), _##i = (y); i < _##i; ++i)
#define FORD(i, x, y) for (decay::type i = (x), _##i = (y); i > _##i; --i)

template
void OOM(T a, string s = "") {
    cerr << s << ":";
    for (auto e:a) cerr << e.first << "," << e.second << " ";
    cerr << endl;
}

template
void OO(T a, string s = "") {
    cerr << s << ":";
    for (auto e:a)cerr << e << " ";
    cerr << endl;
}

template
inline void oo(string str, T val) { cerr << str << val << endl; }

template
inline T read() {
    T x;
    cin >> x;
    return x;
}

int main() {
    set> S;
    string str("PKHT");
    for (auto c : str) {
        for (int i = 1; i <= 13; i++) {
            S.insert(make_pair(c, i));
        }
    }
    string t(read());
    bool flag = true;
    for (int i = 0; i < t.size() / 3; i++) {
        char c = t[i * 3];
        int d = (t[i * 3 + 1] - '0') * 10 + t[i * 3 + 2] - '0';
        pair p = {c, d};
        if (S.find(p) == S.end()) {
            cout << "GRESKA" << endl;
            flag = false;
            break;
        } else {
            S.erase(p);
        }
    }
    if (flag) {
        for (auto c : str) {
            cout << count_if(S.begin(), S.end(), [c](pair pa) -> bool { return pa.first == c; }) << endl;
        }
    }
    return 0;
}

C

C.卡牌对决
时间限制:3s
描述:
有2N张牌,它们的点数分别为1到2N,Alice拿到了其中的N张,Bob拿了剩下的N张,Alice和Bob会进行N轮游戏,在每轮游戏中,Alice和Bob各出了一张牌,出了的牌不能收回,在前N/2轮中,每轮谁的牌点数大谁就赢;在后N/2轮中,每轮谁的牌点数小谁就赢。一直Bob每一轮会出什么牌,试求Alice最多能赢多少轮。

输入
第一行是一个整数N
接下来N行,每行一个整数,表示Bob这轮会出什么
2<=N<=50000,保证N是偶数
输出
输出Alice最多能赢几轮

样例输入

4
1
8
4
3

样例输出

2
 

 

贪心排序

#include 

using namespace std;

typedef long long LL;
#define endl '\n'
#define FOR(i, x, y) for (decay::type i = (x), _##i = (y); i < _##i; ++i)
#define FORD(i, x, y) for (decay::type i = (x), _##i = (y); i > _##i; --i)

template
void OOM(T a, string s = "") {
    cerr << s << ":";
    for (auto e:a) cerr << e.first << "," << e.second << " ";
    cerr << endl;
}

template
void OO(T a, string s = "") {
    cerr << s << ":";
    for (auto e:a)cerr << e << " ";
    cerr << endl;
}

template
inline void oo(string str, T val) { cerr << str << val << endl; }

template
inline T read() {
    T x;
    cin >> x;
    return x;
}

int main() {
    std::iostream::sync_with_stdio(false);
    cin.tie(nullptr);
    cout.tie(nullptr);

    int n(read()), m = n * 2;
    vector A, B;
    map M;
    FOR(i, 1, m + 1)M[i] = true;
    FOR(i, 0, n) {
        int x(read());
        B.push_back(x);
        M[x] = false;
    }
    FOR(i, 1, m + 1)if (M[i])A.push_back(i);

    sort(B.begin(), B.begin() + n / 2);
    sort(B.begin() + n / 2, B.end());
    sort(A.begin(), A.end(), greater());
    reverse(A.begin(), A.begin() + n / 2);
    reverse(A.begin() + n / 2, A.end());

    int win = 0;
    FOR(i, 0, n)if (i < n / 2 and A[i] > B[i] or i >= n / 2 and A[i] < B[i])++win;
    cout << win << endl;
    return 0;
}

 

D

D.自驾游
时间限制:2s
描述:
P省有N个城市,编号分别为1 . . . N,烦烦家住1号城市,N 号城市是省会。P省的交通非常发达,有 M 条有向的高速公路连接这 N 个城市,第 i 条高速公路(1 <= i <= M)从城市 ui 连向 城市 vi.
这天,烦烦想自己开车从家前往省会城市游玩。烦烦是个做事很细致的人,为了有备无患,她决定同时开着 heromap 和 amap 这两个不同的导航软件来帮助自己完成这次旅程。这两个导航软件内部采用了不同的算法,对于第 i 条高速公路(1 <= i <= M), heromap认为通过时间为 Pi 分钟,amap 则认为通过时间为 Qi 分钟,这两个导航软件会根据自己的数据来计算从当前位置到目标位置所需的最短时间是多少,对于第 i 个城市(1 <= i <=N ),记 heromap 认为从 i 到 N 的最短时间为 hero(i), 记 amap 认为从 i 到 N 的最短时间为a(i)。烦烦开车途经某条高速公路(1 <= i <= M)时,如果 heromap 认为从 ui 到 N 不应该走这条路,即 hero(vi) + Pi > hero(ui),则发出一次警告,同样的,如果 amap 认为从 ui 到 N 不应该走这条路, 即 a(i) + Qi > a(ui),也会发出一个警告。现在烦烦希望自己选择一条路径,使得受到的警告总数最少,请你编程解决这一问题。

输入
第一行是一个整数N和M
接下来M行,第 i 行有四个整数 ui, vi, Pi, Qi 分别表示第 i 条边发出的出发点和到达点编号,两个导航软件认为走过这条边所用的时间。
2 <= N <= 10000
1 <= M <= 50000
1 <= ui, vi <= N
输出
输出从 1 走到 N 最少受到多少次警告

样例输入

5 7
3 4 7 1
1 3 2 20
1 4 17 18
4 5 25 3
1 2 10 1
3 5 4 14
2 4 6 5

样例输出

1
 

先反向建图,使用Dijkstra算法那求出hero_dis和amap_dis,然后再用Dijkstra算法求最短路。这个最短路的判断是dis[j.v] > dis[w] + (dis_hero[j.v] + j.p > dis_hero[w]) + (dis_a[j.v] + j.q > dis_a[w])。

 

#include 

using namespace std;

#define endl '\n'
typedef long long LL;

template
void OOM(T a, string s = "") {
    cerr << s << ":\t";
    for (auto e:a) {
        cerr << e.first << "," << e.second << " ";
    }
    cerr << endl;
}

template
void OO(T a, string s = "") {
    cerr << s << ":\t";
    for (auto e:a) {
        cerr << e << " ";
    }
    cerr << endl;
}

template
inline void oo(string str, T val) { cerr << str << val << endl; }

template
inline T read() {
    T x;
    cin >> x;
    return x;
}


#define FOR(i, x, y) for (decay::type i = (x), _##i = (y); i < _##i; ++i)
#define FORD(i, x, y) for (decay::type i = (x), _##i = (y); i > _##i; --i)
struct ZJ{
    int v, p, q;
    ZJ(int v, int p, int q):v(v), p(p), q(q){}
};
void DIJ(int len, int source, int y, vector >&V, vector&dis, int type){
    vectorbook(len+1,false);
    dis[source] = 0;
    for(auto i: V[source]){
        if(type == 0){
            dis[i.v] = i.p;
        }else{
            dis[i.v] = i.q;
        }
    }
    OO(dis, "start print dis = ");
    book[source] = true;
    for(int i = 1; i < len; i++){
        cerr << "i = " << i << endl;
        int w = -1;
        int minDis = INT_MAX;
        for(int j = 1; j <= len; j++){
            if(book[j] || dis[j] >= minDis)continue;
            w = j;
            minDis = dis[j];
        }
        cerr << "w = " << w << "minDis = " << minDis << endl;
        book[w] = true;
        dis[w] = minDis;
        for(auto j: V[w]){
            if(book[j.v])continue;
            if(type == 0){
                cerr << "change dis = " << dis[w]+j.p< dis[w] + j.p){
                    dis[j.v] = dis[w] + j.p;
                }
            }else{
                if(dis[j.v] > dis[w] + j.q){
                    dis[j.v] = dis[w] + j.q;
                }
            }
        }
        OO(dis, "dis= ");
        OO(book, "book= ");
    }
}
int main(){
    ifstream cin("input.txt");
    int n, m;
    cin >> n >> m;
    vector< vector > V1(n+1), V2(n+1);//V1是反向图,V2是原图
    for(int i = 0; i < m; i++){
        int u, v, p, q;
        cin >> u >> v >> p >> q;
        V1[v].emplace_back(ZJ(u, p, q));
        V2[u].emplace_back(ZJ(v, p, q));
    }
    for(int i = 1; i <= n; i++){
        cerr << i <<": ";
        for(auto j : V1[i]){
            cerr << j.v << " " << j.p << " " << j.q << endl;
        }
    }
    vectordis_a(n+1, INT_MAX / 2), dis_hero(n+1, INT_MAX / 2);
    OO(dis_hero);
    OO(dis_a);
    DIJ(n, n, 1, V1, dis_hero, 0);
    OO(dis_hero, "final dis_hero = ");
    DIJ(n, n, 1, V1, dis_a, 1);
    OO(dis_a, "final dis_a = ");
    vectordis(n+1, INT_MAX/2);
    for(auto i:V2[1]){
        dis[i.v] = (dis_hero[i.v] + i.p > dis_hero[1]) + (dis_a[i.v] + i.q > dis_a[1]);
    }
    dis[1] = 0;
    vectorbook(n+1, false);
    book[1] = true;
    for(int i = 1; i < n; i++){
        int w = -1, minDis = INT_MAX/2;
        for(int j = 1; j <= n; j++){
            if(book[j] == 0 and dis[j] < minDis){
                w = j;
                minDis = dis[j];
            }
        }
        cerr << "w = " << w << endl;
        book[w] = true;
        for(auto j : V2[w]){
            if(book[j.v])continue;
            int t = (dis_hero[j.v] + j.p > dis_hero[w]) + (dis_a[j.v] + j.q > dis_a[w]);
            if(dis[j.v] > dis[w] + t){
                dis[j.v] = dis[w] + t;
            }
        }
        OO(dis, "dis = ");
    }
    cout << dis[n] << endl;
    return 0;
}
/*
5 7
3 4 7 1
1 3 2 20
1 4 17 18
4 5 25 3
1 2 10 1
3 5 4 14
2 4 6 5
1
5 7
3 4 7 11
1 3 2 20
1 4 7 18
4 5 2 3
1 2 1 10
3 5 14 4
2 4 6 5
0
4 6
1 2 13 40
2 3 7 12
1 3 15 6
1 4 11 2
2 4 14 1
3 4 29 14
0
 */

 

L.曲奇工厂


时间限制:2s
描述:
曲奇工厂是一个经典好玩的益智游戏,游戏中你的目标是生产至少 C 块曲奇:游戏的规则十分简单; 游戏开始时你有 0 块曲着,每分钟可以手工作出 S 块曲奇。你也可以从 N 个工厂中选择些买下来; 工厂依次编号为 1-N ,买下第 i 个工厂需要花费 Ai 个曲奇饼。但是工厂会为你带来更多收益,买下第 i 个工厂后,每分钟曲奇产出会增加 Bi 块。
对于每个工厂,你只能买一次: 你只能在整数分钟时购买工厂,并且可以一次买多个工厂, 请问达成日标所用最短时间是多少?

输入
输人的第一行是三个整数 N, C 和 S
接下来 N 行,每行两个整数 Ai 和 Bi
1 <=N<= 5
1<= C, S, Ai, Bi <=.10^5
输出
输出得到至少 C 块曲奇,最少要多长时间,
样例输入

2 18 1
6 2
5 1
1
2
3
样例输出

12

这题可以采用动态规划思想,转移方程为dp[j]=max(dp[j],dp[j]-A[i]+(j-index)*B[i])

该动态转移方程的意义为 :

 1.若第j分钟买工厂i,则第j分钟的曲奇饼数量为 dp[j]-A[i]+(j-index)*B[i]

 2.若第j分钟不买工厂i,则第j分钟的曲奇饼数量不变,仍然为dp[j];

因此转移方程为 dp[j]=max(dp[j],dp[j]-A[i]+(j-index)*B[i])

下面为我写的代码,里面有详细的注释

#include 
#include 
#include 
#include 
using namespace std;
int dp[100010];
struct work{
    int A,B;
    
};
bool operator<(struct work temp1,struct work temp2){
    if(temp1.A==temp2.A) return temp1.B>temp2.B;
    return temp1.A>N>>C>>S;
    for(int i=1;i<=N;i++){
        cin>>w[i].A>>w[i].B;
    }//读入数据
    int k=C%S==0?C/S:C/S+1;//k的值为不买任意工厂花费的最少时间
    dp[0]=0;//dp数组dp[i]的意义为前i分钟最大能制造的曲奇饼数量
    for(int i=1;i<=k;i++){
        dp[i]=i*S;//初始化dp数组,不买工厂每分钟制造S个
    }
    sort(w+1,w+N+1);
    do
    {
        for(int i=1;i<=N;i++){
            int index=0;//index的意义为,最早在第index分钟能买的起工厂i
            for(int j=1;j<=k;j++){
                if(dp[j]>=w[i].A){
                    if(index==0){
                        index=j;//赋值得到index
                        
                    }
                    else{
                        dp[j]=max(dp[j],dp[j]-w[i].A+(j-index)*w[i].B);
                        //该动态转移方程的意义为 :
                        // 1.若第j分钟买工厂i,则第j分钟的曲奇饼数量为 dp[j]-A[i]+(j-index)*B[i]
                        // 2.若第j分钟不买工厂i,则第j分钟的曲奇饼数量不变,仍然为dp[j];
                        //因此转移方程为 dp[j]=max(dp[j],dp[j]-A[i]+(j-index)*B[i]) 
                    }          
                }
                //cout<=C){
                if(minx>i) minx=i;
                for(int j=1;j<=k;j++){
                    dp[j]=j*S;//初始化dp数组,不买工厂每分钟制造S个
                }
                break;//输出最小的时间
            }
        }
    }while(next_permutation(w+1,w+N+1));
    cout<

 

K.福报


时间限制:2s
描述:
员工绩效评估对于任何公司都是很重要的,在绩效考核中,员工会就最近完成的工作编写工作反馈。反馈会被递给他们的上级,然后上级根据收到的反馈来决定绩效.
Alice 负责-家知名公司工程部广]的绩效考核系统。该部门遵循树形结构。每位员工都有一个直接上级,最上级是部门总监.
让上级评估其直接下属的表现并不是很有效.经过深人研究,Alice 想出了一个新的绩效考核系统,主要思路是在现有的公司结构中补充每个员工的技术等级,新的绩效评估流程如下,员工要准备他们的工作反馈,然后向所有比他技术等级高的上级(直接上级和间接上级)递交工作反馈;上级需 要花时间审核所有递交给他的工作反馈。
Alice 对这个新系统感到非常满意,但她不确定这在实践中是否可行,她想知道每个员工审核下属工作反馈所需的时间,你能帮她吗?

输入
输人的第一行是整数 E , 员工的总数。接下来有 E 行,第 i 行有三个整数mi,n,t表示第 i 号员工对应的上级编号,他的技术等级,审核他的工作反馈所需要的时间,部门总监没有上级,所以他的上级编号是 -1
1 < E, mi, ri,ti < 10^6
输出
按编号顺序输出每位员工审核下属工作反馈所需时间

 

这道题目采用前缀和的思想,就是求一颗树以每个结点的权值为根的子树的所有权值和,我们从叶子结点开始累加

然后父结点的权值和就等于它的孩子的权值和加上孩子结点的权值

即:

temp[node[i].parent].sum+=(node[i].weight+node[i].sum)

#include 
#include 
#include 
#include
using namespace std;
struct Node{
    int parent;
    int weight;
    int level;
    int sum;
    Node(){
        sum=0;
    }
    
};
bool operator<(const struct Node temp1,const struct Node temp2){
        return temp1.level>E;
    int parent,level,weight;
    for(int i=1;i<=E;i++){
        scanf("%d%d%d",&node[i].parent,&node[i].level,&node[i].weight);
        temp[i]=node[i];
    }
    sort(node+1,node+E+1);
    for(int i=1;i<=E-1;i++){
        temp[node[i].parent].sum+=(node[i].weight+node[i].sum);
    }
    for(int i=1;i<=E;i++){
        printf("%d\n",temp[i].sum);
    }
    

    return 0;
}

H.不要回文


时间限制:2s
描述:
给出一个字符串 S,你需要尽可能少的修改 S 中的字符, 使得 S 不包含长度大于等于 2 的回文子串。

输入
输入的第一行是一个字符串 S, S只包含小写字母
S 的长度大于 5 小于 300
输出
输出使得 S 中不包含长度大于等于 2 的回文, 最少需要修改几个字符 (可以修改成任意字符)
样例输入

abbaa


样例输出

2

 

这道题目很简单,水题,主要知道就是遍历所有可能出现的字串,判断它是否是大于2的回文串,若是回文串,则把回文子串的第四个字符改为不可能出现的字符,这样原串就变为了从修改的字符 后一个字符开始的串,重复上述步骤。

#include 
#include 
#include 
#include
using namespace std;
string s;
bool judge(string temp){
    int mid=temp.size()/2;
    int len=2*mid;
    for(int i=0;i>s;
    int len=s.size();
    
    int ans=0;
    for(int i=0;i<=len-4;i++){
        
        for(int j=i+3;j

由于本次题目的OJ没有开放,且本人没有参加这次比赛,所以代码不保证正确性,仅提供代码和思路,如有错误,请批评指正,谢谢。
 

你可能感兴趣的:(ACM)