题目集地址 2019ICCPC银川
参考题解 2019 ICPC亚洲区域赛银川赛区题解
A Girls Band Party 分组背包
题目地址A Girls Band Party
参考文章Girls Band Party(2019银川A题)
题目大意:给出
n
(
n
≤
100000
)
n(n\leq100000)
n(n≤100000)个物品,每个物品有一个name属性和一个color属性和一个power,再给出5个name值和1个color值。选出5个物品,定义bonus初始为1,每有一个物品的name在给出的name中则
b
o
n
u
s
+
=
10
%
bonus+=10\%
bonus+=10%,每有一个物品的color为给出的color则
b
o
n
u
s
+
=
20
%
bonus+=20\%
bonus+=20%,定义
得
分
=
5
个
物
品
p
o
w
e
r
的
和
×
b
o
n
u
s
得分=5个物品power的和\times bonus
得分=5个物品power的和×bonus,求选出的5个物品得分最高为多少,每个名字只能选一次
思路:分组背包,把名字相同的分为一组,然后把五件物品当作第一变化量,每个的奖励百分比当作第二变化量
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <string>
#include <iostream>
#include <map>
#include <vector>
using namespace std;
const int maxn = 1e5 + 7;
map<string,int>mp1,mp2;
int dp[maxn][6][16];
struct Node
{
int val,num;
string name,color;
bool operator < (const Node&rhs)const
{
return name < rhs.name;
}
}a[maxn];
vector<Node>G[maxn];
void init(int n)
{
memset(dp,-1,sizeof(dp));
mp1.clear();mp2.clear();
for(int i = 1;i <= n;i++)G[i].clear();
}
int main()
{
int T;scanf("%d",&T);
while(T--)
{
int n;scanf("%d",&n);
init(n);
for(int i = 1;i <= n;i++)
{
cin >> a[i].name >> a[i].color >> a[i].val;
}
string tmp;
for(int i = 1;i <= 5;i++)
{
cin >> tmp;mp1[tmp] = 1;
}
cin >> tmp;mp2[tmp] = 2;
sort(a + 1,a + 1 + n);
int cnt = 0;
for(int i = 1;i <= n;i++)
{
if(a[i].name != a[i - 1].name)
{
cnt++;
}
a[i].num = mp1[a[i].name] + mp2[a[i].color];
G[cnt].push_back(a[i]);
}
dp[0][0][0] = 0;
for(int i = 1;i <= cnt;i++)
{
for(int k = 0;k <= 5;k++)
{
for(int q = 0;q <= 15;q++)
{
dp[i][k][q] = dp[i - 1][k][q];
}
}
for(int j = 0;j < G[i].size();j++)
{
int val = G[i][j].val,num = G[i][j].num;
for(int k = 1;k <= 5;k++)
{
for(int q = num;q <= 15;q++)
{
if(dp[i - 1][k - 1][q - num] != -1)
{
dp[i][k][q] = max(dp[i][k][q],dp[i - 1][k - 1][q - num] + val);
}
}
}
}
}
int ans = 0;
for(int i = 0;i <= 5;i++)
{
for(int j = 0;j <= 15;j++)
{
ans = max(ans,dp[cnt][i][j] * (10 + j) / 10);
}
}
printf("%d\n",ans);
}
return 0;
}
B So Easy 思维
题目地址B So Easy
题目大意:一个
n
×
m
n\times m
n×m 矩阵,
n
m
≥
2
n m\geq 2
nm≥2,初始全0,每次可以行+1或列+1。现在某一个数丢失,求它是多少。
思路:有这样一个规律
a
x
y
+
a
z
w
=
a
x
w
+
a
z
y
a_{xy}+a_{zw}=a_{xw}+a_{zy}
axy+azw=axw+azy。
#include <bits/stdc++.h>
#define ll long long
#define INF 0x3f3f3f3f
using namespace std;
const int N=1e3+3;
int maze[N][N];
void solve()
{
int n,px,py;
cin >> n;
for(int i = 1;i <= n;i++)
{
for(int j = 1;j <= n;j++)
{
cin >> maze[i][j];
if(maze[i][j]==-1)
{
px=i;
py=j;
}
}
}
if(px==1&&py==1)
{
cout << maze[2][1]+maze[1][2]-maze[2][2] << endl;
}
else
{
cout << maze[1][py]+maze[px][1]-maze[1][1] << endl;
}
}
int main()
{
// freopen("in.txt","r",stdin);
int t = 1;
// int t;
// scanf("%d",&t);
while(t--)
{
solve();
}
return 0;
}
D
E
G Pot!! 线段树
题目地址G Pot!!
题目大意:维护一个数组,区间乘一个 2 ≤ x ≤ 10 2\leq x\leq 102≤x≤10 的数字,区间查询 pot ( x ) \operatorname{pot}(x)pot(x) 的最大值,其中
pot
(
x
)
:
=
max
p
p
r
i
m
e
,
p
c
∣
x
c
.
\operatorname{pot}(x):=\max_{p\ \mathrm{prime},\ p^c|x}c.
pot(x):=p prime, pc∣xmaxc.
做法:对2,3,5,7分别维护一颗线段树,区间加、区间取max即可。
#include <bits/stdc++.h>
using namespace std;
const int maxn=1e5+10;
struct node {
int val[8],lazy[8];
} seg[maxn<<2];
int n,q,l,r,x,prime[]= {2,3,5,7};
void PushDown(int rt) {
for(int i=0; i<4; i++) {
int t=prime[i];
if(seg[rt].lazy[t]) {
seg[rt<<1].val[t]+=seg[rt].lazy[t];
seg[rt<<1|1].val[t]+=seg[rt].lazy[t];
seg[rt<<1].lazy[t]+=seg[rt].lazy[t];
seg[rt<<1|1].lazy[t]+=seg[rt].lazy[t];
seg[rt].lazy[t]=0;
}
}
}
void PushUp(int rt) {
for(int i=0; i<4; i++) {
int t=prime[i];
seg[rt].val[t]=max(seg[rt<<1].val[t],seg[rt<<1|1].val[t]);
}
}
void Update(int L,int R,int c,int t,int l,int r,int rt) {
if(L<=l&&R>=r) {
seg[rt].val[c]+=t;
seg[rt].lazy[c]+=t;
return ;
}
int mid=(l+r)>>1;
PushDown(rt);
if(L<=mid)
Update(L,R,c,t,l,mid,rt<<1);
if(R>mid)
Update(L,R,c,t,mid+1,r,rt<<1|1);
PushUp(rt);
}
int Query(int L,int R,int l,int r,int rt) {
if(L<=l&&R>=r) {
int res=0;
for(int i=0; i<4; i++) {
int t=prime[i];
res=max(res,seg[rt].val[t]);
}
return res;
}
if(L>r||R<l)return 0;
int mid=(l+r)>>1;
PushDown(rt);
return max(Query(L,R,l,mid,rt<<1),Query(L,R,mid+1,r,rt<<1|1));
}
int main() {
ios::sync_with_stdio(0);
cin.tie(0);
cin >>n>>q;
while(q--) {
string s;
cin >>s;
switch(s[1]) {
case 'U':
cin >>l>>r>>x;
for(int i=0; i<4; i++)
if(x%prime[i]==0) {
if(x==8) {
Update(l,r,prime[i],3,1,maxn,1);
break;
} else if(x==9||x==4) {
Update(l,r,prime[i],2,1,maxn,1);
break;
}
else
Update(l,r,prime[i],1,1,maxn,1);
}
break;
case 'A':
cin >>l>>r;
cout <<"ANSWER "<<Query(l,r,1,maxn,1)<<endl;
break;
}
}
return 0;
}
I Base62 进制转换 数学 大数
题目地址I Base62
题目大意:xyz,三个字符串,给出x进制的z转换成y进制输出。A表示10,a表示36
思路:就是普通的进制转换只不过需要用到大数,先将x进制转为10进制,再将数字转为y进制。
我们不太会用c++的大数,就用了java。
import java.math.BigInteger;
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
// TODO Auto-generated method stub
String z;
int x,y;
Scanner input=new Scanner(System.in);
x=input.nextInt();
y=input.nextInt();
z = input.next();
if(z.equals("0"))
{
System.out.println(0);
return;
}
BigInteger big1=Toten(z, x);
String res=reverse(ToY(big1, y));
System.out.println(res);
}
static String reverse(String str)
{
String s="";
int len = str.length();
for(int i = len-1;i >= 0;i--)
{
s+=str.charAt(i);
}
return s;
}
static String ToY(BigInteger a,int y) {
String res="";
BigInteger zero=new BigInteger("0");
BigInteger ynum=new BigInteger(""+y);
int tnum;
while(!a.equals(zero))
{
tnum=Integer.valueOf(a.remainder(ynum).toString());
res+=inttochar(tnum);
a=a.divide(ynum);
}
return res;
}
static BigInteger Toten(String str,int x) {
BigInteger res=new BigInteger("0");
BigInteger tb;
BigInteger tBigInteger=BigInteger.ONE;
BigInteger k = BigInteger.valueOf(x);
int len = str.length();
for(int i = len-1; i >= 0;i--){
tb=new BigInteger(tBigInteger.toString());
res=res.add(chartoint(str.charAt(i)).multiply(tb));
tBigInteger = tBigInteger.multiply(k);
}
return res;
}
static BigInteger chartoint(Character ch)
{
int t=0;
BigInteger bigInteger;
if(ch>='0'&&ch<='9') {
t = ch-'0';
}
else if(ch>='A'&&ch<='Z') {
t = ch-'A'+10;
}
else if(ch>='a'&&ch<='z') {
t = ch-'a'+36;
}
bigInteger=new BigInteger(""+t);
return bigInteger;
}
static Character inttochar(int n)
{
if(n>=0&&n<=9)
return (char) ('0'+n);
else if(n>=10&&n<=35)
return (char) ('A'+n-10);
else
return (char) ('a'+n-36);
}
}
K
N Fibonacci Sequence 简单题
题目地址N Fibonacci Sequence
题目大意:输出斐波那契数列的前5项
思路:输出1 1 2 3 5即可
#include <iostream>
using namespace std;
int main(){
cout << "1 1 2 3 5" << endl;
return 0;
}