2019 ICPC银川区域赛题解

本文提供了2019年ICPC银川区域赛的完整题解,涵盖了多个难度级别的算法问题,包括《Girls Band Party》、《So Easy》、《Easy Problem》等,涉及加成计算、矩阵操作、数论等多个主题。每个题目均有详细的描述、输入输出样例及解题思路,是参赛者复习和学习的宝贵资料。

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

2019 ICPC银川区域赛题解

——大概是史上最全的版本!


A. Girls Band Party

题目链接

Description

You are currently playing a game called “Garupa”. In an event of the game, you are trying to get more event points. You have nn cards, each with its own name, color, and power. When you play the game, you can put five cards of different names into your deck. The base point of this event is the sum of the power of the cards in your deck. On top of that, the event publishes a color and five names as bonus attributes, which means that each time you have a card with a bonus color in the deck, you end up with a 20 % 20\% 20% increase in event point. And each time you have a card with a bonus name in the deck, you will eventually get 10 % 10\% 10% of the event point (bonus values are calculated by addition, and we round down when calculating the final event point). Please find the maximum event point you will eventually get.

Input

The first line is an integer T   ( 1 ≤ T ≤ 50 ) T~(1 \leq T \leq 50) T (1T50), which is the number of test cases.

For each set of input data, input a positive integer n   ( 5 ≤ n ≤ 100000 ) n~(5 \leq n \leq 100000) n (5n100000) in the first line to indicate the number of cards you have.

The next nn lines, the ii-th line input two strings n a m e i name_i namei, c o l o r i color_i colori and a positive integer p o w e r i   ( 1 ≤ p o w e r i ≤ 50000 ) power_i~(1 \leq power_i \leq 50000) poweri (1poweri50000) separated by spaces, indicating the name, color, and power of the i i i-th card. The input data ensures that there are at least five cards with different names.

The next line input five strings representing the five bonus names. The input data guarantees that the bonus names are different.

The last line input a string representing a bonus color.

The input data ensures that all strings consist of only uppercase and lowercase letters and the max length of them is 10 10 10, and the sum of n n n in all sets of input data does not exceed 1500000 1500000 1500000.

题目大意

每个卡片有一个名字、一个颜色和一个权值。有5种名字的卡片能带来 10 % 10\% 10%的加成,有1种颜色的卡片能带来 20 % 20\% 20%的加成。
让你从n张卡片里选择名字不同的5张卡片。总加成初始为1,若选择的卡片名字出现在5种加成名字中,则总加成 + 10 % +10\% +10%,若选择的卡片颜色与加成颜色一样,则总加成 + 20 % +20\% +20%;基础得分为5张卡片的权值之和, 总 得 分 = 基 础 得 分 ∗ 总 加 成 之 和 总得分=基础得分*总加成之和 =,求最大总得分。

Output

For each set of data, output only one line of a positive integer, indicating the maximum number of bonus points that you will eventually get.

样例输入
1
6
Saaya Power 45000
Kokoro Happy 45000
Kasumi Cool 45000
Rimi Power 45000
Aya Pure 45000
Aya Power 2000
Saaya Tae Kasumi Rimi Arisa
Power
样例输出
382500
题解

所有的牌都可以分为4类
1:名字没有加成,颜色没有加成
2:名字有加成,颜色没有加成
3:名字没有加成,颜色有加成
4:名字有加成,颜色有加成

把类别相同的都放在同一个数组中,把每个数组都按照power从大到小排序。对每个数组去重,每个名字只保留power最高的。
设最后的四个数组为V[1],V[2],V[3],V[4],然后爆搜即可:
每次从V[0],V[1],V[2],V[3]中选取一张牌,优先选power最高的,如果名字重复就跳过。
详细过程见代码与注释。

#include <bits/stdc++.h>
using namespace std;
const int MAXN = 1e5 + 50;
int T, n;
double ans;
//totn为不同的name个数,totc为不同的color个数
int totn, totc;
string ss;
//mpn, mpc分别用来把name、color用数字进行映射代替
map<string, int> mpn, mpc;
int rwdn[6], tr, rwdc;//记录加成名字的标号、加成颜色的标号

struct Info
{
   
    int nam, col, pwr;
}a[MAXN], v[5][MAXN];
int tot[5];
/*
 1: none;
 2: name;
 3: color;
 4: both;
 */

bool cmp1(Info a, Info b)
{
   
    return a.nam == b.nam ? a.pwr > b.pwr : a.nam < b.nam;
}
bool cmp2(Info a, Info b)
{
   
    return a.pwr > b.pwr;
}

set<int> usd;
set<int>::iterator it;
void dfs(int dep, int cntn, int cntc, int pwr, int i1, int i2, int i3, int i4)
{
   
//参数意义:搜索深度,name加成个数,color加成个数,当前总power,四个数组选择到了哪里
    if(dep == 6)
    {
   
        ans = max(ans, (1.0 + 0.1 * cntn + 0.2 * cntc) * pwr);
        return;
    }
    if(i1 <= tot[1] && usd.find(v[1][i1].nam) == usd.end())
    {
   
        usd.insert(v[1][i1].nam);
        dfs(dep+1, cntn, cntc, pwr+v[1][i1].pwr, i1+1, i2, i3, i4);
        usd.erase(v[1][i1].nam);
    }
    else if(i1+1 <= tot[1]) dfs(dep, cntn, cntc, pwr, i1+1, i2, i3, i4);
    if(i2 <= tot[2] && usd.find(v[2][i2].nam) == usd.end())
    {
   
        usd.insert(v[2][i2].nam);
        dfs(dep+1, cntn+1, cntc, pwr+v[2][i2].pwr, i1, i2+1, i3, i4);
        usd.erase(v[2][i2].nam);
    }
    else if(i2+1 <= tot[2]) dfs(dep, cntn, cntc, pwr, i1, i2+1, i3, i4);
    if(i3 <= tot[3] && usd.find(v[3][i3].nam) == usd.end())
    {
   
        usd.insert(v[3][i3].nam);
        dfs(dep+1, cntn, cntc+1, pwr+v[3][i3].pwr, i1, i2, i3+1, i4);
        usd.erase(v[3][i3].nam);
    }
    else if(i3+1 <= tot[3]) dfs(dep, cntn, cntc, pwr, i1, i2, i3+1, i4);
    if(i4 <= tot[4] && usd.find(v[4][i4].nam) == usd.end())
    {
   
        usd.insert(v[4][i4].nam);
        dfs(dep+1, cntn+1, cntc+1, pwr+v[4][i4].pwr, i1, i2, i3, i4+1);
        usd.erase(v[4][i4].nam);
    }
    else if(i4+1 <= tot[4]) dfs(dep, cntn, cntc, pwr, i1, i2, i3, i4+1);
}

void clear()
{
   
    totn = totc = tr = 0;
    memset(tot, 0, sizeof(tot));
    ans = 0;
    mpn.clear(); mpc.clear();
}

int main()
{
   
    scanf("%d", &T);
    while(T--)
    {
   
        scanf("%d", &n);
        for(int i = 1; i <= n; i++)
        {
   
        	//对名字、颜色进行映射标号
            cin >> ss;
            if(mpn[ss]) a[i].nam = mpn[ss];
            else a[i].nam = mpn[ss] = ++totn;
            cin >> ss;
            if(mpc[ss]) a[i].col = mpc[ss];
            else a[i].col = mpc[ss] = ++totc;
            scanf("%d", &a[i].pwr);
        }
        for(int i = 1; i <= 5; i++)
        {
   
        	//对加成name进行标号(未出现过则无意义,不标号)
            cin >> ss;
            if(mpn[ss]) rwdn[++tr] = mpn[ss];
        }
        cin >> ss;
        //对加成color标号,若不存在则标-1
        rwdc = mpc[ss] ? mpc[ss] : -1;
        for(int i = 1; i <= n; i++)
        {
   
        	//将每张卡片分类(标准见上)
            int flag = 1;
            for(int j = 1; j <= tr; j++)
            {
   
                if(a[i].nam == rwdn[j])
                {
   
                    if(a[i].col == rwdc) v[4][++tot[4]] = a[i];
                    else v[2][++tot[2]] = a[i];
                    flag = 0; break;
                }
            }
            if(flag)
            {
   
                if(a[i].col == rwdc) v[3][++tot[3]] = a[i];
                else v[1][++tot[1]] = a[i];
            }
        }
        for(int i = 1; i <= 4; i++)
        {
   
            int sz = tot[i];
            tot[i] = 0;
            //按照name优先、power次优的顺序排序,这样相同的名字都排在了一起,第一个为power最大的
            sort(v[i]+1, v[i]+1+sz, cmp1);
            //去重:同类型且同名的,power较小的肯定不选
            for(int j = 1; j <= sz; j++) if(v[i][j].nam != v[i][j-1].nam) v[i][++tot[i]] = v[i][j];
            //按照power从小到大重新排序
            sort(v[i]+1, v[i]+1+tot[i], cmp2);
        }
        dfs(1, 0, 0, 0, 1, 1, 1, 1);
        int opt = int(ans);
        printf("%d\n", opt);
        clear();
    }
    return 0;
}

B. So Easy

题目链接

Description

Mr. G invents a new game whose rules are given as follows.

Firstly, he has a n × n n \times n n×n matrix, all elements of which are 0 0 0 initially. Then, he follows up with some operations: in each time he chooses a row or a column, and adds an arbitrary positive integer to all the elements in the selected row or column. When all operations have been finished, he hides an element in the matrix and the element is modified to − 1 -1 1.

Now given the final matrix, you are asked to find out what the hidden element should be before the very last hiding operation.

题目大意

一个初始为 n × n n\times n n×n 的矩阵初始全为 0 0 0,经过数次操作(每次操作可以将一行或者一列全都加上一个正整数)后得到了一个最终矩阵。现在把这个矩阵的一个元素改成 − 1 -1 1后给你,求这个元素原先是多少。

Input

The first line contains a single integer n   ( 2 ≤ n ≤ 1000 ) n~(2 \leq n \leq 1000) n (2n1000).

Next nn lines represent the matrix after the operations. Each element in the matrix satisfies − 1 ≤ a i , j ≤ 1000000 -1 \leq a_{i,j} \leq 1000000 1ai,j1000000, and exactly one element is − 1 -1 1.

Output

Output a single integer, the hidden element.

样例输入
3
1 2 1
0 -1 0
0 1 0
样例输出
1
题解

设最终矩阵为A。先将A每行都减去其最小值,得到B;再将B每列都减去其最小值,得到C。C应为零矩阵。

#include<bits/stdc++.h>
using namespace std;
const int MAXN = 1e3 + 10;
const int INF = 1e9;
int n, a[MAXN][MAXN];
int x, y;

int main()
{
   
	scanf("%d", &n);
	for(int i = 1; i <= n; i++)
	{
   
		for(int j = 1; j <= n; j++)
		{
   
			scanf("%d", &a[i][j]);
			if(a[i][j] == -1) {
   x = i; y = j;}
		}
	}
	a[x][y] = INF;
	for(int i = 1; i <= n; i++)
	{
   
		int minn = 1e9;
		for(int j = 1; j <= n; j++) minn = min(minn, a[i][j]);
		for(int j = 1; j <= n; j++) a[i][j] -= minn;
	}
	for(int j = 1; j <= n; j++)
	{
   
		int minn = 1e9;
		for(int i = 1; i <= n; i++) minn = min(minn, a[i][j]);
		for(int i = 1; i <= n; i++) a[i][j] -= minn;
	}
	printf("%d\n", INF - a[x][y]);
	return 0;
}

D. Easy Problem

题目链接

Description

A sequence ( a 1 , a 2 , . . . , a n ) (a_{1},a_{2},...,a_{n}) (a1,a2,...,an) is ( n , m , d ) (n,m,d) (n,m,d)-good if 1 ≤ a i ≤ m   ( 1 ≤ i ≤ n ) 1 \leq a_{i} \leq m~(1 \le i \le n) 1aim (1in) and gcd ⁡ ( a 1 , a 2 , ⋯   , a n ) = d \gcd(a_{1},a_{2},\cdots,a_{n})=d gcd(a1,a2,,an)=d.

Given four integers n , m , d n, m, d n,m,d and k k k, you are asked to calculate the sum of f ( q , k ) f(q, k) f(q,k) for each (n, m, d)-good sequence q q q, where f ( ( a 1 , a 2 , . . . a n ) , k ) = ( a 1 a 2 ⋯ a n ) k f((a_{1},a_{2},...a_{n}),k) = (a_{1}a_{2} \cdots a_{n})^{k} f((a1,a2,...an),k)=(a1a2an)k for the sequence q = ( a 1 , a 2 , . . . a n ) q = (a_{1},a_{2},...a_{n}) q=(a1,a2,...an).

Since the answer could be very large, you only need to output the answer modulo 59964251 59964251 59964251.

Input

The first line is an integer T   ( 1 ≤ T ≤ 20 ) T~(1 \leq T \leq 20) T (1T20), which is the number of test cases.

For each test case, the first line contains four integers n   ( 1 ≤ n ≤ 1 0 100000 ) , m   ( 1 ≤ m ≤ 100000 ) , d   ( 1 ≤ d ≤ 100000 ) , k   ( 1 ≤ k ≤ 1 0 9 ) n~(1 \leq n \leq 10^{100000}), m~(1 \leq m \leq 100000), d~(1 \leq d \leq 100000), k~(1 \leq k \leq 10^9) n (1n10100000),m (1m100000),d (1d100000),k (1k109), which are described in the problem description.

Output

For each test case, output a line containing a single integer.

样例输入
1
3 3 3 1
样例输出
27
题解
step1

由于 gcd ⁡ ( a 1 , a 2 , ⋯   , a n ) = d \gcd(a_{1},a_{2},\cdots,a_{n})=d gcd(a1,a2,,an)=d,因此我们可以将每个数提出一个 d d d,在式子外面乘上一个 ( d k ) n (d^k)^n (dk)n
剩下可选取的数:

[ ⌊ m d ⌋ ⌊ m d ⌋ . . . ⌊ m d ⌋ ⌊ m d ⌋ . . . . . . . . . . . . . . . 3 3 . . . 3 3 2 2 . . . 2

评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值