PAT (Advanced Level) Practice (1 - 15)

目录

1001 A+B Format

1002 A+B for Polynomials

1003 Emergency

1004 Counting Leaves

1005 Spell It Right

1006 Sign In and Sign Out

1007 Maximum Subsequence Sum

1008 Elevator

1009 Product of Polynomials

1010 Radix

1011 World Cup Betting

1012 The Best Rank

1013 Battle Over Cities

1014 Waiting in Line

1015 Reversible Primes


1001 A+B Format

        求A+B, 但是输出每隔三位数字加一个",".

void solve() {
    int a, b;
    cin>>a>>b;
    string s = to_string(a + b);
    int n = s.size();
    int idx = 0;
    if(s[0] == '-') idx ++;
    int cnt = 0;
    string s1;
    for(int i = n - 1; i >= 0; i --) {
        cnt ++;
        s1 += s[i];
        if(cnt % 3 == 0 && i > idx) s1 += ',';
    }
    reverse(s1.begin(), s1.end());
    cout<<s1<<endl;
}
1002 A+B for Polynomials

        求多项式A+B后每项的系数,需要注意输出需要按照输入形式输出,即项数从大到小,遇到系数为0跳过,保留一位小数.

double mp[1010];

void solve() {
    int n;
    cin>>n;
    
    for(int i = 0; i < n; i ++) {
        int a; double b;
        cin>>a>>b;
        mp[a] += b;
    }
    cin>>n;
    for(int i = 0; i < n; i ++) {
        int a; double b;
        cin>>a>>b;
        mp[a] += b;
    }
    int cnt = 0;
    for(int i = 0; i <= 1000; i ++) {
        if(mp[i] != 0) cnt ++;
    }
    printf("%d", cnt);
    for(int i = 1000; i >= 0; i --) {
        if(mp[i] != 0) printf(" %d %.1lf", i, mp[i]);
    }
}
1003 Emergency

       求出发点到终点的最短路径有多少条以及最大权值是多少.

int n, m, st, ed;
int dist[510];
bool vis[510];
vector<PII> v[510];
int w[510];
int ans[510];
int sum[510];

void solve() {
    cin>>n>>m>>st>>ed;
    for(int i = 0; i < n; i ++) cin>>w[i];
    for(int i = 1; i <= m; i ++) {
        int x, y, s;
        cin>>x>>y>>s;
        v[x].push_back({y, s});
        v[y].push_back({x, s});
    } 
    
    priority_queue<PII, vector<PII>, greater<PII>> q;
    memset(dist, 0x3f, sizeof dist);
    q.push({0, st});
    dist[st] = 0;
    ans[st] = w[st];
    sum[st] = 1;
    while(q.size()) {
        auto [d, now] = q.top();
        q.pop();
        if(vis[now]) continue;
        vis[now] = 1;
        for(auto k : v[now]) {
            if(dist[now] + k.second < dist[k.first]) {
                dist[k.first] = dist[now] + k.second;
                ans[k.first] = max(ans[k.first], ans[now] + w[k.first]);
                q.push({dist[k.first], k.first});
                sum[k.first] = sum[now];
            }
            else if(dist[now] + k.second == dist[k.first]) {
                sum[k.first] += sum[now];
                q.push({dist[k.first], k.first});
                ans[k.first] = max(ans[k.first], ans[now] + w[k.first]);
            }
        }
        
    }
    cout<<sum[ed]<<' '<<ans[ed];
}
1004 Counting Leaves

        统计一个森林里每层有多少个叶子节点.

vector<int> v[100];
int n, m;
bool rt[100];
int dep[100], mx;

void dfs(int u, int d) {
    int f = 1;
    for(auto k : v[u]) {
        dfs(k, d + 1);
        f = 0;
    }
    dep[d] += f;
    mx = max(mx, d); 

}

void solve() {
    cin>>n>>m;
    int id, k;
    while(m --) {
        cin>>id>>k;
        while(k --) {
            int x;
            cin>>x;
            v[id].push_back(x);
            rt[x] = 1;
        }
    }
    for(int i = 1; i <= n; i ++) {
        if(!rt[i]) dfs(i, 0);
    }
    for(int i = 0; i <= mx; i ++) {
        cout<<dep[i];
        if(i != mx) cout<<' ';
    }
}
1005 Spell It Right

        输出各数位的英文表示.

map<char, string> mp;

void init() {
    mp['0'] = "zero";
    mp['1'] = "one";
    mp['2'] = "two";
    mp['3'] = "there";
    mp['4'] = "four";
    mp['5'] = "five";
    mp['6'] = "six";
    mp['7'] = "seven";
    mp['8'] = "eight";
    mp['9'] = "nine";
}

void solve() {
    init();
    string s;
    cin>>s;
    int sum = 0;
    int n = s.size();
    for(int i = 0; i < n; i ++) sum += s[i] - '0';
    s = to_string(sum);
    n = s.size();
    for(int i = 0; i < n; i ++) {
        cout<<mp[s[i]];
        if(i != n - 1) cout<<' ';
    }
}
1006 Sign In and Sign Out

        询问第一个到达的人和最后一个离开的人.

int n;
struct node{
    string name, st, ed;
}t;

void solve() {
    cin>>n;
    vector<node> v;
    while(n --) {
        string s, s1, s2;
        cin>>s>>s1>>s2;
        v.push_back({s, s1, s2});
    }
    sort(v.begin(), v.end(), [&](node a, node b) {return a.st < b.st;});
    cout<<v[0].name<<' ';
    sort(v.begin(), v.end(), [&](node a, node b){return a.ed > b.ed;});
    cout<<v[0].name; 
}
1007 Maximum Subsequence Sum

        求最大连续区间和以及该区间首尾元素,要求区间左右端点尽可能小。

int n;
ll mx = -1, st = -1, ed = -1, l;

void solve() {
    cin>>n;
    ll sum = 0;
    ll a[n + 1];
    for(int i = 0; i < n; i ++) cin>>a[i];
    bool f = 1;
    for(int i = 0; i < n; i ++) {
        if(sum > 0) sum += a[i];
        else {
            l = a[i];
            sum = a[i];
        }
        if(sum > mx) {
            mx = sum;
            st = l;
            ed = a[i];
        }
    }
    if(mx == -1) mx = 0, st = a[0], ed = a[n - 1];
    cout<<mx<<' ';
    cout<<st<<' '<<ed; 
}
1008 Elevator

        模拟上下楼梯。

int n;
int now;
int ans;

void solve() {
    cin>>n;
    int x;
    while(n --) {
        cin>>x;
        ans += 5;
        if(x < now) ans += (now - x) * 4;
        else ans += (x - now) * 6; 
        now = x;
    }
    cout<<ans;
}
1009 Product of Polynomials

多项式A*B,输出规范和1002一样,相当于B的每一项乘A的每一项再相加

int n;
map<int, double> mp;
map<int, double> ans;

void solve() {
    cin>>n;
    while(n --) {
        int a; double b;
        cin>>a>>b;
        mp[a] += b;
    }
    cin>>n;
    while(n --) {
        int a; double b;
        cin>>a>>b;
        map<int, double> res;
        for(auto [x, y] : mp) {
            res[x + a] = y * b; 
        }
        for(auto [x, y] : res) ans[x] += y; 
    }
    vector<pair<int, double>> v;
    for(auto [x, y] : ans) {
        if(y != 0)
        v.push_back({x, y});
    }
    printf("%d", v.size());
    for(int i = v.size() - 1; i >= 0; i --) {
        printf(" %d %.1lf", v[i].first, v[i].second);
    }
}
1010 Radix

       给出n1, n2, tag和radix,tag为1表示n1为radix进制,tag为2表示n2为radix进制,另一个数进制未知。问是否有一个尽可能小的答案使n1和n2在十进制下相等。

        思路:方便起见,如果tag为2,交换n1,n2,使确定的数为n1, 不确定的数为n2。

a数组是n2从高到低的每个数位,base是我们要求的进制位。由于题目设置了每个数位的数最大是35,可以看出如果答案很大的话,后面的项和第一项相差巨大,这时候暴力枚举一定会超时,但是我们这时可以大概求出l最小的取值,然后再往右枚举几位就能判断出是否会相等。把n1转化成10进制数后除以a1,再取(n-1)的根,大概是l最小的范围。如果答案比较小的话,暴力枚举。

string s1, s2;
int tag, radix;

void solve() {
    cin>>s1>>s2>>tag>>radix;
    reverse(s1.begin(), s1.end());
    reverse(s2.begin(), s2.end());
    if(tag == 2) {string s = s1; s1 = s2; s2 = s;}
    ll n1 = 0;
    ll base = 1;
    for(int i = 0; i < s1.size(); i ++) {
        int num;
        if(islower(s1[i])) num = s1[i] - 'a' + 10;
        else num = s1[i] - '0';
        n1 += 1ll * base * num;
        base *= radix;
    }
    ll n2 = 0;
    int l = 0;
    for(char ch : s2) {
        int num;
        if(islower(ch)) num = ch - 'a' + 10;
        else num = ch - '0';
        l = max(num, l);
    }
    l ++;
    int n = s2.size();
    int w;
    if(islower(s2[n - 1])) w = s2[n - 1] - 'a' + 10;
    else w = s2[n - 1] - '0'; 
    int l1 = n1 / w;
    if(n > 1) {
        l1 = pow(l1, 1.0 / (n - 1));
        if(l1 - l > 1000) l = l1;
    }
    while(n2 < n1) {
        n2 = 0;
        base = 1;
        for(char ch : s2) {
            int num;
            if(islower(ch)) num = ch - 'a' + 10;
            else num = ch - '0';
            n2 += 1ll * base * num;
            base *= l;
        }
        l ++;
    }
    if(n1 == n2) cout<<l - 1;
    else cout<<"Impossible";
}
1011 World Cup Betting

        找到三个最大的数然后做运算。

double x[3];
double ans = 1.0;

void solve() {
    for(int i = 0; i < 3; i ++) {
        double mx = 0.0;
        for(int j = 0; j < 3; j ++) {
            cin>>x[j];
            mx = max(mx, x[j]);
        }
        if(mx == x[0]) cout<<"W ";
        else if(mx == x[1]) cout<<"T ";
        else cout<<"L ";
        ans *= mx;
    }
    ans *= 0.65;
    ans -= 1.0;
    ans *= 2.0;
    printf("%.2lf", ans);
}
1012 The Best Rank

       询问学生四项成绩最好的一个排名是多少。

struct node {
    string id;
    int c, m, e, a;

};
int n, m;

void solve() {
    vector<node> v;    
    cin>>n>>m;
    string s;
    int C, M, E, A;
    for(int i = 0; i < n; i ++) {
        cin>>s>>C>>M>>E;
        A = (C + M + E) / 3;
        v.push_back({s, C, M, E, A});
    }
    map<string, int> res;
    map<string, char> ans;
    sort(v.begin(), v.end(), [&](node a, node b) { return a.a > b.a;});
    int pre = -1, idx = 0;
    for(int i = 0; i < n; i ++) {
        if(pre != v[i].a) idx = i;
        res[v[i].id] = idx;
        ans[v[i].id] = 'A';
        pre = v[i].a;
    }
    pre = -1, idx = 0;
    sort(v.begin(), v.end(), [&](node a, node b) { return a.c > b.c;});
    for(int i = 0; i < n; i ++) {
        if(pre != v[i].c) idx = i;
        if(idx < res[v[i].id]) {
            res[v[i].id] = idx;
            ans[v[i].id] = 'C';
        }
        pre = v[i].c;
    }
    pre = -1, idx = 0;
    sort(v.begin(), v.end(), [&](node a, node b) { return a.m > b.m;});
    for(int i = 0; i < n; i ++) {
        if(pre != v[i].m) idx = i;
        if(idx < res[v[i].id]) {
            res[v[i].id] = idx;
            ans[v[i].id] = 'M';
        }
        pre = v[i].m;
    }
    pre = -1, idx = 0;
    sort(v.begin(), v.end(), [&](node a, node b) { return a.e > b.e;});
    for(int i = 0; i < n; i ++) {
        if(pre != v[i].e) idx = i;
        if(idx < res[v[i].id]) {
            res[v[i].id] = idx;
            ans[v[i].id] = 'E';
        }
        pre = v[i].e;
    }
    while(m --) {
        string s1;
        cin>>s1;
        if(res.count(s1)) 
        cout<<res[s1] + 1<<' '<<ans[s1]<<endl;
        else cout<<"N/A"<<endl;
    }
    
}
1013 Battle Over Cities

        有一个无向图,问删掉一个点和它所连的边后,至少加多少条边能让图联通。

(n很小,直接暴力了) 每次新建一个并查集找有多少个连通块。

int n, m, k;
int p[N];

int find(int u) {
    if(u != p[u]) p[u] = find(p[u]);
    return p[u];
}

void solve() {
    cin>>n>>m>>k;
    vector<PII> v;
    for(int i = 1; i <= m; i ++) {
        int x, y;
        cin>>x>>y;
        v.push_back({x, y});
    }
    while(k --) {
        int x;
        cin>>x;
        for(int i = 1; i <= n; i ++) p[i] = i; 
        for(auto [y, z] : v){
            if(y == x || z == x) continue;
            int px = find(y), py = find(z);
            if(px != py) {
                p[px] = py;
            }
        }
        map<int, bool> mp;
        for(int i = 1; i <= n; i ++) {
            if(i == x) continue;
            mp[find(i)] = 1;
        }
        cout<<mp.size() - 1<<endl;
    }
} 
1014 Waiting in Line

        模拟排队,询问每个人的结束时间。需要注意开始时间要小于17:00, 结束时间要小于18:00.

        

int n, m, k, q;

void solve() {
    cin>>n>>m>>k>>q;
    queue<int> line[n + 1];
    int idx = 1;
    int t[k + 1];
    for(int i = 1; i <= k; i ++) cin>>t[i];
    for(int j = 1; j <= m; j ++) {
        for(int i = 1; i <= n; i ++) {
            if(idx > k) break;
            line[i].push(idx ++);
        }
        if(idx > k) break;
    }
    int cnt = 0;
    int last[n + 1];
    for(int i = 1; i <= n; i ++) {
        if(!line[i].size()) last[i] = -1;
        int j = line[i].front();
        last[i] = t[j];

    }
    int ans[k + 1];
    while(cnt < k) {
        int mn = -1;
        for(int i = 1; i <= n; i ++) {
            if(last[i] == -1) continue;
            if(last[mn] > last[i] || mn == -1) mn = i;
        }
        int j = line[mn].front();
        ans[j] = last[mn];
        line[mn].pop();
        cnt ++;
        if(idx <= k) line[mn].push(idx ++);
        if(line[mn].size()) last[mn] += t[line[mn].front()];
        else last[mn] = -1;
    }
     while(q --) {
        int x; cin>>x;
        if(ans[x] - t[x] >= 540 || ans[x] >= 600) printf("Sorry\n");
        else printf("%02d:%02d\n", 8 + ans[x] / 60, ans[x] % 60);
    }
} 
1015 Reversible Primes

        询问一个数和他的对应的反转数是否都为质数。

int n, radix;
int pri[N], c;
bool vis[N];

void oula() {
    vis[0] = vis[1] = 1;
	for(int i = 2; i < N; i ++) {
		if(!vis[i]) pri[c ++] = i;
		for(int j = 0; i * pri[j] < N; j ++) {
			vis[i * pri[j]] = 1;
			if(i % pri[j] == 0) break; 
		}
	}
}

void solve() {
	cin>>radix;
	string s;
	int m = n;
	while(m) {
		int t = m % radix;
		s += ('0' + t);
		m /= radix;
	}
	reverse(s.begin(), s.end());
	int base = 1;
	for(int i = 0; i < s.size(); i ++) {
		int t = (s[i] - '0') * base;
		base *= radix;
		m += t;
	}
	if(!vis[n] && !vis[m]) cout<<"Yes"<<endl;
	else cout<<"No"<<endl;
}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值