[Atcoder Grand Contest 004] Tutorial
Link:
A:
……
#include <bits/stdc++.h> using namespace std;
long long a,b,c;
int main()
{
scanf("%lld%lld%lld",&a,&b,&c);
if(a%==||b%==||c%==) puts("");
else printf("%lld",min(a*b,min(a*c,b*c)));
return ;
}
Problem A
B:
从0到$n-1$枚举$k$
对于每一个$k$,$res=k*x+\sum_{i=1}^n min(dat[i-1],dat[i-2],..dat[i-k])$
接下来对于每个$i$预处理出$pre[i][j]$表示第$i$个数及其之前$j$个数中的最小值
这样就能在$O(n)$内算出每个$k$时的结果
#include <bits/stdc++.h> using namespace std;
typedef long long ll;
const int MAXN=;
ll x,res=1e15;
int n,pre[MAXN][MAXN]; int main()
{
scanf("%d%lld",&n,&x);
for(int i=;i<n;i++) scanf("%d",&pre[i][]);
for(int i=;i<n;i++)
for(int j=;j<n;j++)
{
int cur=(i-j+n)%n;
pre[i][j]=min(pre[i][j-],pre[cur][]);
} for(int i=;i<n;i++)
{
ll t=i*x;
for(int j=;j<n;j++) t+=pre[j][i];
res=min(res,t);
}
printf("%lld",res);
return ;
}
Problem B
C:
纯构造题
虽然算是奇技淫巧,但还是有些规律可循的……
一个条件:边界上没有紫色的部分
这其实就暗示我们要根据这个条件构造连通性,两颜色各占一条边
接下来可以先让两种颜色完全没有重叠,再对应有重叠的部分特殊处理:
1、奇数行(不含边界)为蓝色,偶数行为红色
2、将紫色部分补成两种颜色
这样就既保证只有紫色部分有两种颜色,有保证两种颜色分别连通了!
官方题解的例子:
#include <bits/stdc++.h> using namespace std;
const int MAXN=;
int n,m;
char a[MAXN][MAXN],b[MAXN][MAXN],dat[MAXN][MAXN];
int main()
{
scanf("%d%d",&n,&m);
for(int i=;i<=n;i++) scanf("%s",dat[i]+);
for(int i=;i<=n;i++)
{
a[i][]=b[i][m]='#';
if(i&) for(int j=;j<=m-;j++) a[i][j]='#';
else for(int j=;j<=m-;j++) b[i][j]='#';
} for(int i=;i<=n;i++)
for(int j=;j<=m;j++)
a[i][j]=(dat[i][j]!='#'&&a[i][j]!='#')?'.':'#',
b[i][j]=(dat[i][j]!='#'&&b[i][j]!='#')?'.':'#';
for(int i=;i<=n;i++) printf("%s\n",a[i]+);
puts("");
for(int i=;i<=n;i++) printf("%s\n",b[i]+);
return ;
}
Problem C
感觉构造题还是有一些通用思想的
对于此题,就利用了弱化条件的思想
(1)先不考虑有部分要重叠,只保证无重叠且各自连通
(2)再考虑怎么保证任意添加都不影响连通性
D:
首先能比较简单得证出1必须为自环(否则包含1的环中的其他点一定不满足要求)
此时$n$个点,$n-1$条边形成一棵树,
于是将问题转化为将一棵树切割成高度不大于$k-1$的子树的最小值
(特判:子树的根为1时高度不大于$k$即可)
这样从叶子节点向上贪心选取即可(一定不能从上向下贪心!)
#include <bits/stdc++.h> using namespace std;
const int MAXN=1e5+;
vector<int> G[MAXN];
int n,k,dat[MAXN],dp[MAXN],res=; void dfs(int x)//要从叶子节点开始推!
{
for(int i=;i<G[x].size();i++)
if(G[x][i]!=dat[x]) dfs(G[x][i]);
if(++dp[x]>=k&&dat[x]!=) res++,dp[x]=;
dp[dat[x]]=max(dp[dat[x]],dp[x]);
} int main()
{
scanf("%d%d",&n,&k);
for(int i=;i<=n;i++) scanf("%d",&dat[i]);
if(dat[]!=) res++,dat[]=;
for(int i=;i<=n;i++) G[dat[i]].push_back(i); dfs();printf("%d",res);
return ;
}
Problem D
一般树上递推/贪心都要从叶子节点向上推
从上往下直接贪心一般都有问题
E:
把所有机器人的移动看成出口的移动
这样出口每向一个方向移动一格会ban掉相反方向的一整行/列
而产生的贡献的长度由其向垂直的两个方向移动的距离及产生的限制限定
这样设$dp[u][d][l][r]$表示出口已向四个方向移动$u,d,l,r$后的最值,加个前缀和$O(1)$算贡献即可
#include <bits/stdc++.h> using namespace std;
#define X first
#define Y second
#define pb push_back
typedef double db;
typedef long long ll;
typedef pair<int,int> P;
const int MAXN=;
char s[MAXN][MAXN];
int n,m,x,y;
short dp[MAXN][MAXN][MAXN][MAXN];
short line[MAXN][MAXN],col[MAXN][MAXN];
void upd(short &a,short b){a=max(a,b);} int main()
{
scanf("%d%d",&n,&m);
for(int i=;i<=n;i++)
{
scanf("%s",s[i]+);
for(int j=;j<=m;j++)
{
if(s[i][j]=='E') x=i,y=j;
line[i][j]=line[i][j-]+(s[i][j]=='o');
col[i][j]=col[i-][j]+(s[i][j]=='o');
}
} short res=;
dp[][][][]=;
for(int u=;u<x;u++) for(int d=;d<=n-x;d++)
for(int l=;l<y;l++) for(int r=;r<=m-y;r++)
{
if(!(u+d<max(x,n-x+)&&l+r<max(y,m-y+))) continue;
short &cur=dp[u][d][l][r];res=max(res,cur);
int L=max(r+,y-l),R=min(y+r,m-l),D=min(x+d,n-u),U=max(x-u,d+);
if(u++d<x) upd(dp[u+][d][l][r],cur+line[x-u-][R]-line[x-u-][L-]);
if(d++u<=n-x) upd(dp[u][d+][l][r],cur+line[x+d+][R]-line[x+d+][L-]);
if(l++r<y) upd(dp[u][d][l+][r],cur+col[D][y-l-]-col[U-][y-l-]);
if(r++l<=m-y) upd(dp[u][d][l][r+],cur+col[D][y+r+]-col[U-][y+r+]);
}
printf("%d",res);
return ;
}
Problem E
F:
$Atcoder$风格神仙题,第一步就想不到系列……
树的情况:
(不能随便找一个点为根贪心,如果要贪心需要枚举所有点为根)
一般此类相邻点同时操作想到黑白染色!
一棵树必然能黑白染色,每次操作就是将两点颜色取反,目标是所有点皆呈反颜色
由于能翻转的条件是必须要一黑一白,那么就能看成黑点的移动,移动一步就要翻转一次
接下来对每条边计算贡献,考虑儿子的子树中黑白点的差$s[i]$,贡献则为$abs(\sum s[i])$
如果总的黑白点数不等则无解
奇环的情况
由于非树边连接的点同颜色,每次操作相当于同时增加/减少2个黑点
因此只有在黑白点差为偶数时有解,此时将$x,y$到根路径上点的$s[i]$修改后再同样计算即可
偶环的情况
非树边连接的点颜色不同,每次操作相当于移黑点,关键在于确定转移数量
设$x,y$到根路径上的点分别为$a_i,b_i$,$x$向$y$转移了$k$
则要求$min{\sum |a_i-k|+|b_i+k|+|k|}$
此式的几何意义就是$a_i,-b_i,0$到$k$的距离和,明显最优$k$就是中位数,同样修改计算
#include <bits/stdc++.h> using namespace std;
#define X first
#define Y second
#define pb push_back
typedef double db;
typedef long long ll;
typedef pair<int,int> P;
const int MAXN=1e5+;
struct edge{int nxt,to;}e[MAXN<<];
ll res=;
int lca,dep[MAXN],sum[MAXN],f[MAXN];
int n,m,fx,fy,head[MAXN],x,y,tot,TOT,cnt,t[MAXN]; void add_edge(int x,int y)
{
e[++TOT]=(edge){head[x],y};head[x]=TOT;
e[++TOT]=(edge){head[y],x};head[y]=TOT;
}
void dfs(int x,int anc,int val)
{
sum[x]=val;tot+=val;
dep[x]=dep[anc]+;f[x]=anc;
for(int i=head[x];i;i=e[i].nxt)
if(e[i].to!=anc)
{
if(dep[e[i].to])
{fx=x;fy=e[i].to;continue;}
dfs(e[i].to,x,-val),sum[x]+=sum[e[i].to];
}
}
int LCA(int x,int y)
{
if(dep[x]<dep[y]) swap(x,y);
int t=dep[x]-dep[y];
for(int i=;i<=t;i++) x=f[x];
while(x!=y) x=f[x],y=f[y];
return x;
} int main()
{
scanf("%d%d",&n,&m);
for(int i=;i<=m;i++)
scanf("%d%d",&x,&y),add_edge(x,y);
dfs(,,); if(m==n-)
{
if(tot) return puts("-1"),;
for(int i=;i<=n;i++) res+=abs(sum[i]);
}
else if((dep[fx]-dep[fy])%==)
{
if(tot%) return puts("-1"),;
lca=LCA(fx,fy);tot=-tot/;res+=abs(tot); for(int k=fx;k;k=f[k]) sum[k]+=tot;
for(int k=fy;k;k=f[k]) sum[k]+=tot;
for(int i=;i<=n;i++) res+=abs(sum[i]);
}
else
{
if(tot) return puts("-1"),;
lca=LCA(fx,fy);
for(int k=fx;k!=lca;k=f[k])
t[++cnt]=sum[k],dep[k]=-;
for(int k=fy;k!=lca;k=f[k])
t[++cnt]=-sum[k],dep[k]=-;
t[++cnt]=;
sort(t+,t+cnt+);int val=t[cnt/]; for(int i=;i<=n;i++)
if(~dep[i]) res+=abs(sum[i]);
for(int i=;i<=cnt;i++)
res+=abs(t[i]-val);
}
printf("%d",res);
return ;
}
Problem F
[Atcoder Grand Contest 004] Tutorial的更多相关文章
- AtCoder Grand Contest 004
AtCoder Grand Contest 004 A - Divide a Cuboid 翻译 给定一个\(A*B*C\)的立方体,现在要把它分成两个立方体,求出他们的最小体积差. 题解 如果有一条 ...
- AtCoder Grand Contest 004 C:AND Grid
题目传送门:https://agc004.contest.atcoder.jp/tasks/agc004_c 题目翻译 给你一张网格图,指定的格子是紫色的,要求你构造出两张网格图,其中一张你可以构造一 ...
- AtCoder Grand Contest 004 C - AND Grid
题意: 给出一张有紫色点的网格,构造一张红点网格和一张蓝点网格,使红蓝点的交集为紫色点. 保证网格四周没有紫色点. 构造一下,使蓝点和红点能够到每个点. #include<bits/stdc++ ...
- [Atcoder Grand Contest 003] Tutorial
Link: AGC003 传送门 A: 判断如果一个方向有,其相反方向有没有即可 #include <bits/stdc++.h> using namespace std; ]; map& ...
- [Atcoder Grand Contest 002] Tutorial
Link: AGC002 传送门 A: …… #include <bits/stdc++.h> using namespace std; int a,b; int main() { sca ...
- [Atcoder Grand Contest 001] Tutorial
Link: AGC001 传送门 A: …… #include <bits/stdc++.h> using namespace std; ; ]; int main() { scanf(& ...
- AtCoder Grand Contest 004题解
传送门 \(A\) 咕咕 int a,b,c; int main(){ scanf("%d%d%d",&a,&b,&c); if((a&1^1)|( ...
- AtCoder Grand Contest 012
AtCoder Grand Contest 012 A - AtCoder Group Contest 翻译 有\(3n\)个人,每一个人有一个强大值(看我的假翻译),每三个人可以分成一组,一组的强大 ...
- AtCoder Grand Contest 011
AtCoder Grand Contest 011 upd:这篇咕了好久,前面几题是三周以前写的... AtCoder Grand Contest 011 A - Airport Bus 翻译 有\( ...
随机推荐
- 多种方法过Codeforces Round #270的A题(奇偶法、打表法和Miller_Rabin(这个方法才是重点))
题目链接:http://codeforces.com/contest/472/problem/A 题目: 题意:哥德巴赫猜想是:一个大于2的素数一定可以表示为两个素数的和.此题则是将其修改为:一个大于 ...
- js_返回上一页(兼容苹果手机)
返回上一页功能是常见的功能. 常用的有以下三种代码: window.history.go(-1); //返回上一页 window.history.back(); //返回上一页 //如果要强行刷新的话 ...
- 关于this问题
对于关键字this,其实很好理解,谁调用我就指向谁.下面举个例子说明: 其实这也是在学习闭包中的一个案例: var name = "The window"; var obj = { ...
- linux中字符串转换函数 simple_strtoul【转】
转自:http://blog.csdn.net/tommy_wxie/article/details/7480087 Linux内核中提供的一些字符串转换函数: lib/vsprintf.c [htm ...
- [转载]关于python字典类型最疯狂的表达方式
一个Python字典表达式谜题 让我们探究一下下面这个晦涩的python字典表达式,以找出在python解释器的中未知的内部到底发生了什么. # 一个python谜题:这是一个秘密 # 这个表达式计算 ...
- sql server查看创建表的代码,表定义
1.查看建表语句在“对象资源管理器”中找到要导出的表,选中该表并单击右键,“编写表脚本为(S)”/“CREATE到(C)”/“新查询编辑器窗口”即可查看该表的建表语句.2.导出建表语句在“对象资源管理 ...
- printf格式化输出
基本格式 printf [format] [文本1] [文本2] .. 常用格式替换符 %s 字符串 %f 浮点格式 %c ASCII字符,即显示对应参数的第一个字符 %d,%i 十进制整数 %o 八 ...
- Python Flask 配置文件
1. 什么是配置文件? 就是当程序调用的一些参数,文件路径,方法或者类放到一个文件中, 当下次需要修改的一个参数的时候,不用再从所有关联的程序中找到该参数挨个修改, 比较繁琐.像Django中,程序启 ...
- php上传文件限制
客户端限制(客户端限制在实际上是无法阻止上传): 通过表单隐藏域限制上传文件的最大值 <input type=’hidden’ name=’MAX_FILE_SIZE’ value=’字节数’ ...
- SnagIt截图后无法在编辑器打开,不显示截图内容的解决办法(转)
方法1: 用SnagIt截图后,弹出的编辑器里不显示刚才截图的内容,解决办法如下: 完全退出Snagit和编辑器,删除以下文件夹: Win7用户 C:\Users\Administrator\AppD ...