CCPC-Wannafly Summer Camp #1(部分解题报告)
A:Birthday
时间限制: 1 Sec 内存限制: 256 MB
题目描述
恬恬的生日临近了。宇扬给她准备了一个大蛋糕。
正如往常一样,宇扬在蛋糕上插了n支蜡烛,并把蛋糕分为m个区域。因为某种原因,他必须把第i根蜡烛插在第ai个区域或第bi个区域。区域之间是不相交的。宇扬在一个区域内同时摆放x支蜡烛就要花费x2的时间。宇扬布置蛋糕所用的总时间是他在每个区域花的时间的和。
宇扬想快些见到恬恬,你能告诉他布置蛋糕最少需要多少时间吗?
输入
第一行包含两个整数n,m(1 ≤ n ≤ 50, 2 ≤ m ≤ 50)。
接下来n行,每行两个整数ai, bi(1 ≤ ai, bi ≤ m)。
输出
一个整数表示答案.
样例输入
3 3
1 2
1 2
1 2
样例输出
5
唉,还是大佬的题解写的好,所以感谢wls大佬分享思路 Orz。。。
思路:考虑费用流时把每个part拆成n个点,选择第i个点的代表为放置i块蛋糕和(i - 1)块蛋糕的时间差,
这个时间差是递增的,因此在费用流的过程中必定会从小到大选择
具体建图:
左边n个点代表n个蛋糕,右边m * n个点代表m个part,每个part拆成n个点。源点向每个左边的点连一条流量1费用0的边,每个右边的点向汇点连一条流量1费用0的编。
每个蛋糕向可以放的两个part的所有点连边,连向第i个点的费用为i^2 - (i - 1)^2,流量为1。这样求最小费用流既为答案。
#include"bits/stdc++.h"
using namespace std;
#define M 1100
const int inf=0x7fffffff;
struct node{
int u,v,c,f,next; //C为花费,F为flow流量
}e[M*40];
int pre[M],dis[M],head[M],t;
int vis[M];
void add1(int u,int v,int c,int f){
e[t].u=u;
e[t].v=v;
e[t].c=c;
e[t].f=f;
e[t].next=head[u];
head[u]=t++;
}
void add(int u,int v,int c,int f){
add1(u,v,c,f);
add1(v,u,-c,0); //反向边流量初始为零,如果走反向边费用正好和原边抵消
}
int spfa(int s,int t){
int i,u,v;
queue<int>q;
q.push(s);
memset(vis,0,sizeof(vis));
memset(pre,-1,sizeof(pre));
for(i=s;i<=t;i++)
dis[i]=inf;
dis[s]=0;
while(!q.empty()){
u=q.front();
q.pop();
for(i=head[u];i!=-1;i=e[i].next)
{
v=e[i].v;
if(e[i].f&&dis[v]>dis[u]+e[i].c) //找到一条最小费用流
{
dis[v]=dis[u]+e[i].c;
pre[v]=i; //记录路径
if(!vis[v])
{
vis[v]=1;
q.push(v);
}
}
}
vis[u]=0;
}
if(dis[t]!=inf)
return 1;
return 0;
}
void solve(int s,int t){
int ans=0,i,j;
int flow=0,cost=0; //总流量、总费用
while(spfa(s,t)){
int minf=inf;
for(i=pre[t];i!=-1;i=pre[e[i].u]){
if(e[i].f<minf)
minf=e[i].f;
}
flow+=minf; //该条路径的流量
for(i=pre[t];i!=-1;i=pre[e[i].u]){
j=i^1;
e[i].f-=minf;
e[j].f+=minf;
}
cost+=dis[t]*minf; //单位运费和乘以流量得费用
}
printf("%d\n",cost);
}
int main(){
int i,u,v,c,n,m;
while(scanf("%d%d",&n,&m)==2){
t=0;
memset(head,-1,sizeof(head));
for(i=1;i<=n;i++){
scanf("%d%d",&u,&v);
add(0,i,0,1);
add(i,u+n,0,1);
add(i,v+n,0,1);
}
for(int i=1 ; i<=m ; ++i){
for(int j=1 ; j<=99 ; j+=2){//99 = 2*50-1;
add(i+n,n+m+1,j,1);
}
}
solve(0,n+m+1);
}
return 0;
}
B: Board
时间限制: 1 Sec 内存限制: 256 MB
题目描述
恬恬有一个n × n的数组。她在用这个数组玩游戏:
开始时,数组中每一个元素都是0。
恬恬会做某些操作。在一次操作中,她可以将某一行的所有元素同时加上一个值,也可以将某一列的所有元素同时加上一个值。
在几次操作后,一个元素被隐藏了。你能帮助她回忆隐藏的数是几吗?
输入
第一行一个整数n(1 ≤ n ≤ 1000)。
接下来n行每行n个整数表示数组a。
第(i + 1)行的第j个元素表示aij(aij = - 1或0 ≤ aij ≤ 10000)。 - 1表示隐藏的元素。
输出
仅一个整数表示答案。
样例输入
3
1 2 1
0 -1 0
0 1 0
样例输出
1
这题思路同样为wls大佬给出,Orz wls 。。。
把格子N染色,第i行第j列格子的颜色为(i + j) % N。那么每次操作时,必定是N种不同的颜色都有一格被操作到,
因此最后任何颜色格子的和必定是相等的。因此只需要记录每种颜色格子的和,
并算出缺失格子的颜色C,用其余颜色的和减去颜色C的和即可
#include<bits/stdc++.h>
using namespace std;
int arr[1010][1010];
int a[1010], b[1010];
int main()
{
int n;
while(~scanf("%d", &n)){
memset(a, 0, sizeof(a));
memset(b, 0, sizeof(b));
int maxn = 10010, x, y;
for(int i = 1; i <= n; i++) {
maxn = 10010;
for(int j = 1; j <= n; j++) {
scanf("%d", &arr[i][j]);
if(arr[i][j] != -1){
maxn = min(maxn, arr[i][j]);
}
if(arr[i][j] == -1) {
x = i;
y = j;
}
}
a[i] = maxn;
}
int maxm;
for(int i = 1; i <= n; i++) {
int maxm = 10010;
for(int j = 1; j <= n; j++) {
if(arr[j][i] != -1){
maxm = min(maxm, arr[j][i]);
}
}
b[i] = maxm;
}
if(x == 1 && y == 1)cout << (a[x] + b[y]) - max((a[x+1]+b[y] - arr[x+1][y]),(a[x]+b[y+1]-arr[x][y+1])) << endl;
else if(x==n && y==1)cout << (a[x] + b[y]) - max((a[x-1]+b[y] - arr[x-1][y]),(a[x]+b[y+1]-arr[x][y+1])) << endl;
else if(x==1&&y==n)cout << (a[x] + b[y]) - max((a[x]+b[y-1] - arr[x][y-1]),(a[x+1]+b[y]-arr[x+1][y])) << endl;
else if(x==n&&y==n)cout << (a[x] + b[y]) - max((a[x-1]+b[y] - arr[x-1][y]),(a[x]+b[y-1]-arr[x][y-1])) << endl;
else if(x==1)cout << (a[x] + b[y]) - (a[x+1]+b[y]-arr[x+1][y]) << endl;
else if(x==n)cout << (a[x] + b[y]) - (a[x-1]+b[y]-arr[x+1][y]) << endl;
else cout << (a[x] + b[y]) - (a[x+1]+b[y] - arr[x+1][y]) << endl;
}
return 0;
}
D: Growth
时间限制: 1 Sec 内存限制: 256 MB
题目描述
弱弱有两个属性a和b,这两个属性初始的时候均为0,每一天他可以通过努力,让a涨1点或b涨1点。
为了激励弱弱努力学习,我们共有n种奖励,第i种奖励有xi,yi,zi三种属性,若a ≥ xi且b ≥ yi,则弱弱在接下来的每一天都可以得到zi的分数。
问m天以后弱弱最多能得到多少分数。
输入
第一行一个两个整数n和m(1 ≤ n ≤ 1000,1 ≤ m ≤ 2000000000)。
接下来n行,每行三个整数xi,yi,zi(1 ≤ xi, yi ≤ 1000000000,1 ≤ zi ≤ 1000000)。
输出
一行一个整数表示答案。
样例输入
2 4
2 1 10
1 2 20
样例输出
50
提示
在样例中,弱弱可以这样规划:第一天a涨1,第二天b涨1,第三天b涨1,第四天a涨1。
共获得0 + 0 + 20 + 30 = 50分。
Orz wls。。。
把奖励的x拿出来从小到大排序,得到x1,x2,...,xn。
把奖励的y拿出来从小到大排序,得到y1,y2,...,yn。
用v[i][j]表示a值到达xi,b值达到yi时接下来每天可以得到的奖励。
v[i][j] = v[i - 1][j] + v[i][j - 1] - v[i - 1][j - 1] + t[i][j]
其中t[i][j]为满足x=i,y=j的奖励的总和。
用f[i][j]表示a值达到xi,b值达到yj时已经拿到的奖励的最大值。
f[i][j] + (x[i + 1] - x[i] - 1) * t[i][j] + t[i + 1][j] -> f[i + 1][j]
f[i][j] + (y[j + 1] - y[j] - 1) * t[i][j] + t[i][j + 1] -> f[i][j + 1]
最后统计一下答案就可以了。
不过这题有一个离散化不好写,我也是借鉴大佬的写法,
#include<bits/stdc++.h>
using namespace std;
#define ios1 ios::sync_with_stdio(0)
#define ios2 cin.tie(0)
#define ll long long
#define inf 0x7ffffffff
typedef pair<int, int> P;
map<P, int>mp;
set<int>sx, sy;
const int maxn = 1200;
int n, m;
int xx[maxn], yy[maxn];
ll dp[maxn][maxn], v[maxn][maxn];
int x[maxn], y[maxn], z[maxn];
int main() {
ios1; ios2;
while(cin >> n >> m) {
int xi = 1, yi = 1;
for(int i = 0; i < n; i++) {
cin >> x[i] >> y[i] >> z[i];
if(mp.count(P(x[i], y[i])) == 0)mp[P(x[i], y[i])] = z[i];
else mp[P(x[i], y[i])] += z[i];
if(sx.count(x[i]) == 0){sx.insert(x[i]);xx[xi++] = x[i];}
if(sy.count(y[i]) == 0){sy.insert(y[i]);yy[yi++] = y[i];}
}
sort(xx, xx + xi);
sort(yy, yy + yi);//离散化
memset(dp, 0, sizeof(dp));
memset(v, 0, sizeof(v));
for(int i = 1; i < xi; i++) {
for(int j = 1; j < yi; j++) {
if(mp.count(P(xx[i], yy[j])) == 0)v[i][j] = v[i-1][j] + v[i][j-1] - v[i-1][j-1];
else v[i][j] = v[i-1][j] + v[i][j-1] - v[i-1][j-1] + mp[P(xx[i], yy[j])];
}
}
for(int i = 0; i < xi; i++) {
for(int j = 0; j < yi; j++) {
dp[i+1][j] = max(dp[i+1][j], dp[i][j] + (xx[i+1] - xx[i] - 1) * v[i][j] + v[i+1][j]);
dp[i][j+1] = max(dp[i][j+1], dp[i][j] + (yy[j+1] - yy[j] - 1) * v[i][j] + v[i][j+1]);
}
}
ll ans = 0;
for(int i = 1; i < xi; i++) {
for(int j = 1; j < yi; j++) {
ll r = dp[i][j] + (m - xx[i] - yy[j]) * v[i][j];
ans = max(ans, r);
}
}
cout << ans << endl;
}
return 0;
}
CCPC-Wannafly Summer Camp #1(部分解题报告)的更多相关文章
- 2020 CCPC Wannafly Winter Camp Day1 C. 染色图
2020 CCPC Wannafly Winter Camp Day1 C. 染色图 定义一张无向图 G=⟨V,E⟩ 是 k 可染色的当且仅当存在函数 f:V↦{1,2,⋯,k} 满足对于 G 中的任 ...
- CCPC Wannafly Winter Camp Div2 部分题解
Day 1, Div 2, Prob. B - 吃豆豆 题目大意 wls有一个\(n\)行\(m\)列的棋盘,对于第\(i\)行第\(j\)列的格子,每过\(T[i][j]\)秒会在上面出现一个糖果, ...
- 2020 CCPC Wannafly Winter Camp Day1 Div.1& F
#include<bits/stdc++.h> #define forn(i, n) for (int i = 0; i < int(n); i++) #define fore(i, ...
- 2020 CCPC Wannafly Winter Camp Day1 - I. K小数查询(分块)
题目链接:K小数查询 题意:给你一个长度为$n$序列$A$,有$m$个操作,操作分为两种: 输入$x,y,c$,表示对$i\in[x,y] $,令$A_{i}=min(A_{i},c)$ 输入$x,y ...
- 2020 CCPC Wannafly Winter Camp Day2-K-破忒头的匿名信
题目传送门 sol:先通过AC自动机构建字典,用$dp[i]$表示长串前$i$位的最小代价,若有一个单词$s$是长串的前$i$项的后缀,那么可以用$dp[i - len(s)] + val(s)$转移 ...
- 2020 CCPC Wannafly Winter Camp Day1-F-乘法
题目传送门 sol:二分答案$K$,算大于$K$的乘积有多少个.关键在于怎么算这个个数,官方题解上给出的复杂度是$O(nlogn)$,那么计算个数的复杂度是$O(n)$的.感觉写着有点困难,自己写了一 ...
- Mutual Training for Wannafly Union #1解题报告
---恢复内容开始--- q神等人组织的vjudge上的多校训练,题目基本上都来自于CF,#1是上周进行的,参加后感觉收获很多,因为上周准备期中比较忙,解题报告现在补上. 比赛地址(兼题目地址) A题 ...
- CH Round #56 - 国庆节欢乐赛解题报告
最近CH上的比赛很多,在此会全部写出解题报告,与大家交流一下解题方法与技巧. T1 魔幻森林 描述 Cortana来到了一片魔幻森林,这片森林可以被视作一个N*M的矩阵,矩阵中的每个位置上都长着一棵树 ...
- 二模13day1解题报告
二模13day1解题报告 T1.发射站(station) N个发射站,每个发射站有高度hi,发射信号强度vi,每个发射站的信号只会被左和右第一个比他高的收到.现在求收到信号最强的发射站. 我用了时间复 ...
- BZOJ 1051 最受欢迎的牛 解题报告
题目直接摆在这里! 1051: [HAOI2006]受欢迎的牛 Time Limit: 10 Sec Memory Limit: 162 MBSubmit: 4438 Solved: 2353[S ...
随机推荐
- 有助于提高"锁"性能的几点建议
有助于提高"锁"性能的几点建议 1.减少锁持有时间 public synchronized void syncMethod() { othercode1(); mutextMeth ...
- Linux : 性能监测相关命令
[参考文章]:Linux命令大全 [参考文章]:Linux 运行进程实时监控pidstat命令详解 1. 进程级别的监测命令 1.1 top top命令可以实时动态地查看系统的整体运行情况,是一个综 ...
- Scala函数式编程(三)
Scala既是一门面向对象(OOP)语言,又是一门函数式编程(FP)语言.作为一门支持函数式编程的语言,Scala鼓励面向表达式编程(EOP)模型.简单来说,EOP中每个语句都有返回值.这一模式很明显 ...
- java并发编程(四)----(JUC)Lock锁初探
首先我们来回忆一下上一节讲过的synchronized关键字,该关键字用于给代码段或方法加锁,使得某一时刻它修饰的方法或代码段只能被一个线程访问.那么试想,当我们遇到这样的情况:当synchroniz ...
- Java虚拟机——Java内存区域
1.运行时区域 Java虚拟机在执行Java程序的时候会把它管理的内厝划分为若干个不同功能的数据区域,如图所示 首先是程序计数器,程序计数器可以理解为当前程序执行的字节码的行号指示器,计数器中的数据即 ...
- java封装 redis 操作 对象,list集合 ,json串
/** * 功能说明: * 功能作者: * 创建日期: * 版权归属:每特教育|蚂蚁课堂所有 www.itmayiedu.com */package com.redis.service; import ...
- ElasticSearch 安装与使用
目录 Elastic Search Docker中安装ElasticSearch Elastic Search API得使用 创建Index: 修改Index Mapping: 修改Index Set ...
- SpringBoot 缓存模块
默认的缓存配置 在诸多的缓存自动配置类中, SpringBoot默认装配的是SimpleCacheConfigguration, 他使用的CacheManager是 CurrentMapCacheMa ...
- ASP.NET Core MVC 之区域(Area)
区域(Area)是一个 ASP.NET MVC 功能,用于将相关功能组织为一个单独的命名空间(用于路由)和文件结构(用于视图).使用区域通过向控制器和操作添加 一个路由参数(area)来创建用于路由目 ...
- Django+zTree构建组织架构树
树,因其清晰明了的展现形式而被广泛的使用 日常的开发过程中我们需要经常与"树"打交道,例如公司的组织架构树.服务器的项目归属树,管理后台侧边树等等,本篇文章介绍关于树的两个内容 多 ...