AtCoder Grand Contest 030题解
第一次套刷AtCoder
体验良好
Poisonous Cookies
cout<<b+min(c,a+b+);
Tree Burning
难度跨度有点大啊
可以证明当第一次转向之后,接下来每次的方向都和前一次相反
因为转向后再往相同方向走一定不如初始就往该方向走然后转两次向
枚举初始往哪个方向走以及走几步,前缀和优化即可
#include<ctime>
#include<cmath>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<queue>
#include<vector>
#define rt register int
#define ll long long
using namespace std;
inline ll read(){
ll x=;char zf=;char ch=getchar();
while(ch!='-'&&!isdigit(ch))ch=getchar();
if(ch=='-')zf=-,ch=getchar();
while(isdigit(ch))x=x*+ch-'',ch=getchar();return x*zf;
}
void write(ll y){if(y<)putchar('-'),y=-y;if(y>)write(y/);putchar(y%+);}
void writeln(const ll y){write(y);putchar('\n');}
int k,m,n,x,y,z,cnt,ans;ll ret;
int a[];
ll hz[],qz[],qzh[];
void calc(){
for(rt i=n-;i>=;i--)hz[i]=hz[i+]+2ll*(n-i)*a[i];
qz[]=qzh[]=a[];
for(rt i=;i<=n;i++)qz[i]=qz[i-]+(2ll*i-)*a[i],qzh[i]=qzh[i-]+a[i];
ll ans=;
for(rt i=;i<=n;i++){
ans+=a[i];int md=i+n>>;
ret=max(ret,ans-hz[md+]-(qz[md]-qz[i]-(qzh[md]-qzh[i])*2ll*i)+qzh[n]*(n-i-));
}
}
int main(){
int L=read();n=read();a[++n]=L;
for(rt i=;i<n;i++)a[i]=read();
for(rt i=n;i>=;i--)a[i]-=a[i-];
calc();reverse(a+,a+n+);calc();
cout<<ret;
return ;
}
Coloring Torus
清真构造题
若$ k\leq n$显然可以构一个$ k*k$的正方形,第$ i$行全填$ i$即可
当$ n < k \leq 2n$时,尝试从斜向入手
发现每个斜行可以交错填写数字,这样能填写的数字就能达到$ 2n$级别了
#include<ctime>
#include<cmath>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<queue>
#include<vector>
#define p 1000000007
#define inv2 500000004
#define rt register int
#define ll long long
using namespace std;
inline ll read(){
ll x=;char zf=;char ch=getchar();
while(ch!='-'&&!isdigit(ch))ch=getchar();
if(ch=='-')zf=-,ch=getchar();
while(isdigit(ch))x=x*+ch-'',ch=getchar();return x*zf;
}
void write(ll y){if(y<)putchar('-'),y=-y;if(y>)write(y/);putchar(y%+);}
void writeln(const ll y){write(y);putchar('\n');}
int k,m,n,x,y,z,cnt,ans[][];
int main(){
k=read();
if(k<=){
writeln(k);
for(rt i=;i<=k;i++)for(rt j=;j<=k;j++)cout<<i<<" \n"[j==k];
return ;
}
writeln(n=);
for(rt i=;i<=n;i++){
ans[][i]=i;
for(rt x=n,y=i%n+;x!=;x--,y=y%n+)ans[x][y]=i;
}
for(rt i=n+;i<=k;i++){
if(i+i&)ans[][i]=i;
for(rt x=n,y=i%n+;x!=;x--,y=y%n+)if(i+y&)ans[x][y]=i;
}
for(rt i=;i<=n;i++)for(rt j=;j<=n;j++)cout<<ans[i][j]<<" \n"[j==n];
return ;
}
Inversion Sum
比B和C都清真多了...
设$ f[i][j][k]$表示经过$ i$次操作,$ a_j>a_k$的方案数
容易发现每次操作只对$ O(n)$级别的状态进行了非乘2的修改,其他都只是继承状态然后$ *2$
不妨把状态改成经过$ i$次操作,每次操作有$ 50\%$概率交换两个数,求逆序对的期望
滚动数组之后可以$ O(n^2)$解决转移,最后乘上$ 2^q$即可
#include<ctime>
#include<cmath>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<queue>
#include<vector>
#define p 1000000007
#define inv2 500000004
#define rt register int
#define ll long long
using namespace std;
inline ll read(){
ll x=;char zf=;char ch=getchar();
while(ch!='-'&&!isdigit(ch))ch=getchar();
if(ch=='-')zf=-,ch=getchar();
while(isdigit(ch))x=x*+ch-'',ch=getchar();return x*zf;
}
void write(ll y){if(y<)putchar('-'),y=-y;if(y>)write(y/);putchar(y%+);}
void writeln(const ll y){write(y);putchar('\n');}
int k,m,n,x,y,z,cnt,ans;
int f[][],g[][],a[];
int main(){
n=read();m=read();
for(rt i=;i<=n;i++)a[i]=read();
for(rt i=;i<=n;i++)
for(rt j=;j<=n;j++)if(a[i]>a[j])f[i][j]=;
for(rt i=;i<=m;i++){
x=read();y=read();
for(rt j=;j<=n;j++)g[x][j]=f[x][j],g[j][x]=f[j][x],g[y][j]=f[y][j],g[j][y]=f[j][y];
f[x][y]=f[y][x]=1ll*(g[x][y]+g[y][x])*inv2%p;
for(rt j=;j<=n;j++){
const int v1=1ll*(g[x][j]+g[y][j])*inv2%p,v2=1ll*(g[j][x]+g[j][y])*inv2%p;
if(j!=y&&j!=x)f[x][j]=v1,f[j][x]=v2;
if(j!=x&&j!=y)f[y][j]=v1,f[j][y]=v2;
}
} int ans=;
for(rt i=;i<n;i++)
for(rt j=i+;j<=n;j++)(ans+=f[i][j])%=p;
for(rt i=;i<=m;i++)ans=ans*%p;
cout<<ans;
return ;
}
Less than 3
神仙题!
我们在两个01串中的所有“01”结构之间连一条红线,“10”结构之间连一条蓝线
特判$ n \leq 2$之后发现两个01串等价的充要条件是这两个01串的红蓝线一一对应
发现每次改变非边界的数只会导致一条红/蓝线左移一位或右移一位
改变边界上的数可能会导致生成一条新的红/蓝线或使一条红/蓝线消失不见
容易发现移动不能使同一位置有多条线且线的颜色始终保持红蓝对应
我们可以把边界理解为有无限多条颜色交错的红蓝线
枚举上面的每条红线对应下面的每条红线,红线对答案的贡献就是每组相互对应的线的距离和 蓝线同理
数据范围允许暴力枚举对应$ O(n^2)$通过此题
#include<ctime>
#include<cmath>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<queue>
#include<vector>
#define rt register int
#define ll long long
using namespace std;
inline ll read(){
ll x=;char zf=;char ch=getchar();
while(ch!='-'&&!isdigit(ch))ch=getchar();
if(ch=='-')zf=-,ch=getchar();
while(isdigit(ch))x=x*+ch-'',ch=getchar();return x*zf;
}
void write(ll y){if(y<)putchar('-'),y=-y;if(y>)write(y/);putchar(y%+);}
void writeln(const ll y){write(y);putchar('\n');}
int k,m,n,x,y,z,cnt,ans,ret;
int a[],b[],t1,t2;
char c[],s[];
int calc(){
t1=t2=;
for(rt i=;i<=n;i++)b[++t2]=;
for(rt i=;i<n;i++)if(c[i]==''&&c[i+]=='')a[++t1]=i;
for(rt i=;i<n;i++)if(s[i]==''&&s[i+]=='')b[++t2]=i;
for(rt i=;i<=n;i++)b[++t2]=n;int nowmin=;
for(rt i=;i<=t2-n+;i++){
int ans=;
for(rt j=;j<i;j++)if(b[j])ans+=b[j];
for(rt j=;j<t1;j++)ans+=abs(a[j+]-b[i+j]);
for(rt j=t1;b[i+j]!=n;j++)ans+=n-b[i+j];
nowmin=min(nowmin,ans);
}
return nowmin;
}
int main(){
n=read();
scanf("%s",c+);scanf("%s",s+);
if(n==&&c[]!=s[])writeln();
else if(n==&&c[]!=s[]&&c[]==c[]&&s[]==s[])writeln();
else {
ret=calc();
for(rt i=;i<=n;i++)c[i]=''+''-c[i],s[i]=''+''-s[i];
ret+=calc();cout<<ret;
}
return ;
}
Permutation and Minimum
正推推不出来的DP题启示我们弃疗倒着推
显然两个位置如果都不是$ -1$就可以扔掉
设有cnt组两个位置都是$ -1$则最终答案需要乘上$ cnt!$因为这些组可以任意交换位置
设$ f[i][j][k]$表示已经填了不小于$ i$的所有数,有$ j$个在序列中出现过的数没有被匹配,有$ k$个在原数列中未出现过的数没有被匹配
假设当前数在原序列出现过则可以匹配一个未出现过的数或自己变成一个未被匹配的数
不能匹配一个出现过的数的原因是假设相邻两个数都不是-1则要被扔掉
假设当前数在原序列中未出现过则可以匹配一个未出现过的数,一个出现过的数或自己成为未被匹配的数
注意如果匹配一个出现过的数有$ j$种匹配方式
直接$ O(n^3)DP$即可
#include<ctime>
#include<cmath>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<queue>
#include<vector>
#define p 1000000007
#define rt register int
#define ll long long
using namespace std;
inline ll read(){
ll x=;char zf=;char ch=getchar();
while(ch!='-'&&!isdigit(ch))ch=getchar();
if(ch=='-')zf=-,ch=getchar();
while(isdigit(ch))x=x*+ch-'',ch=getchar();return x*zf;
}
void write(ll y){if(y<)putchar('-'),y=-y;if(y>)write(y/);putchar(y%+);}
void writeln(const ll y){write(y);putchar('\n');}
int k,m,n,x,y,z,cnt,ans;
int a[];bool vis[],nt[];
int q[],t;
int f[][][];
int main(){
n=read();
for(rt i=;i<=*n;i++){
a[i]=read();if(a[i]!=-)vis[a[i]]=;
if(i&^){
if(a[i]==-&&a[i-]==-)cnt++;
if(a[i]!=-&&a[i-]!=-)nt[a[i]]=nt[a[i-]]=;
}
}
for(rt i=;i<=*n;i++)if(!nt[i])if(vis[i])q[++t]=;else q[++t]=;n=t;
//q=1在原数列中
f[n][][]=;
for(rt i=n;i>=;i--){
for(rt j=;j<=n/;j++)
for(rt k=;k<=n/;k++)if(f[i][j][k]){
const int v=f[i][j][k];
if(q[i]){
(f[i-][j+][k]+=v)%=p;
if(k)(f[i-][j][k-]+=v)%=p;
}else {
(f[i-][j][k+]+=v)%=p;
if(k)(f[i-][j][k-]+=v)%=p;
if(j)(f[i-][j-][k]+=1ll*v*j%p)%=p;
}
}
}
int ans=f[][][];
for(rt i=;i<=cnt;i++)ans=1ll*ans*i%p;
cout<<ans;
return ;
}
AtCoder Grand Contest 030题解的更多相关文章
- AtCoder Grand Contest 017 题解
A - Biscuits 题目: 给出 \(n\) 个物品,每个物品有一个权值. 问有多少种选取方式使得物品权值之和 \(\bmod\space 2\) 为 \(p\). \(n \leq 50\) ...
- Atcoder Grand Contest 030 F - Permutation and Minimum(DP)
洛谷题面传送门 & Atcoder 题面传送门 12 天以前做的题了,到现在才补/yun 做了一晚上+一早上终于 AC 了,写篇题解纪念一下 首先考虑如果全是 \(-1\) 怎么处理.由于我 ...
- Atcoder Grand Contest 054 题解
那天晚上由于毕业晚会与同学吃饭喝酒没打 AGC,第二天稍微补了下题,目前补到了 E,显然 AGC 的 F 对于我来说都是不可做题就没补了(bushi A 简单题,不难发现如果我们通过三次及以上的操作将 ...
- AtCoder Grand Contest 030 (AGC030) C - Coloring Torus 构造
原文链接https://www.cnblogs.com/zhouzhendong/p/AGC030C.html 题解 才发现当时是被题意杀了. 当时理解的题意是“对于任意的 (i,j) ,颜色 i 和 ...
- AtCoder Grand Contest 031题解
题面 传送门 题解 比赛的之后做完\(AB\)就开始发呆了--简直菜的一笔啊-- \(A - Colorful\ Subsequence\) 如果第\(i\)个字母选,那么它前面任意一个别的字母的选择 ...
- Coloring Torus(Atcoder Grand Contest 030 C)
怎么外国都喜欢考脑筋急转弯…… 题意 输入 $k$,要求构造一个 $n\times n$ 的矩阵($n$ 自选),使得恰好用 $k$ 中颜色把每个点都染色,并且同一种颜色的格子周围 相邻的每种颜色数量 ...
- AtCoder Grand Contest 039 题解
传送门 \(A\) 首先只有一串的情况下,遇到相同的肯定是改后面那一个最优,然后两串的话可能要分奇偶讨论一下 //quming #include<bits/stdc++.h> #defin ...
- AtCoder Grand Contest 017题解
传送门 \(A\) 直接转移就是了 typedef long long ll; const int N=55; ll f[N][2];int a[N],n,p; int main(){ scanf(& ...
- AtCoder Grand Contest 015题解
传送门 \(A\) 找到能达到的最大的和最小的,那么中间任意一个都可以被表示出来 typedef long long ll; int n,a,b;ll res; int main(){ scanf(& ...
随机推荐
- VUE路由新页面打开的方法总结
平常做单页面的场景比较多,所以大部分的业务是在同一个页面进行跳转.要通过VUE路由使用新页面打开且传递参数,可以采用以下两个方法: 1.router-link的target <router-li ...
- IDEA Can't Update No tracked branch configured for branch master or the branch doesn't exist.
IDEA Can't Update No tracked branch configured for branch master or the branch doesn't exist.To make ...
- springfox-swagger之swagger-bootstrap-ui
swagger-bootstrap-ui是国内的一个swagger开源项目,从发起到现在已经有三年了.初次体验了一下,觉得还是挺不错的,就如当初使用mybatis-plus那样,因为有了mybatis ...
- linux-----docker
docker简介 Docker时Docker.Lnc公司开源的一个基于LXC技术之上搭建的Container容器引擎,源代码托管在Github上,基于Go语言并遵从Apache2.0协议开源. Doc ...
- C语言中printf,scanf,puts,%%等输出格式
#include<stdio.h> int main(void){ int a; printf("请输入一个整数,程序求取他的最后一位数字:"); s ...
- 算法笔记-exgcd
扩展欧几里得 扩展欧几里德算法是用来在已知a, b求解一组x,y, 使它们满足贝祖等式: ax+by = gcd(a, b) =d(解一定存在,根据数论中的相关定理). 扩展欧几里德常用在求解模线性方 ...
- 安装Mediamanager 后Messenger后无法登录
安装MediaManager以后Messenger无法登录,提示无法连接服务,出现以下信息. 解决办法,进入控制面板,卸载"Microsoft URL Scan"程序,即可解决.
- Appium 客户端类库
Appium 支持以下语言的客户端类库: 语言 Ruby Python Java JavaScript PHP C# Objective-C 锁定注意,一些方法类似 endTestCoverage() ...
- OO第一次单元总结
第一次总结性博客 16071070 陈泽寅 2019.3.23 一.第一单元所学总结 首先先来总结一下第一单元我所学到的知识以及所感所悟.第一个单元,是我第一次接触JAVA语言,并且再使用了几次之后, ...
- UOJ14 UER #1 DZY Loves Graph(最小生成树+并查集)
显然可以用可持久化并查集实现.考虑更简单的做法.如果没有撤销操作,用带撤销并查集暴力模拟即可,复杂度显然可以均摊.加上撤销操作,删除操作的复杂度不再能均摊,但注意到我们在删除时就可以知道他会不会被撤销 ...