AtCoder Grand Contest 037
Preface
这篇咕了可能快一个月了吧,正好今天晚上不想做题就来补博客
现在还不去复习初赛我感觉我还是挺刚的(微笑)
A - Dividing a String
考虑最好情况把每个字符串当作一个来看,考虑不合法的情况怎么处理
可以很容易地发现再怎么差我长度分成\(1,2,1,2,\cdots\)的样子就好了,因此字符串最长为\(2\)
贪心地把后面的数和前面合并即可
#include<cstdio>
#include<cstring>
#define RI register int
#define CI const int&
using namespace std;
const int N=200005;
char s[N]; int n,ans,pos;
int main()
{
scanf("%s",s+1); n=strlen(s+1); ans=n; pos=1;
for (RI i=2;i<=n;++i)
if (s[i]==s[pos]) --ans,pos=i+2,i+=2; else pos=i;
return printf("%d",ans),0;
}
B - RGB Balls
这道题我想了比C题长了一个小时你敢相信
首先不考虑顺序,最后乘上\(n!\),那么我们考虑答案\(\sum (c_i-a_i)=\sum c_i-\sum a_i\),要么就是在\(\sum c_i\)确定的情况下让\(\sum a_i\)最大,或者是在\(\sum a_i\)确定的情况下让\(\sum c_i\)最小
那么我们考虑从后忘前做,考虑当前匹配的是\(R\),那么一旦之前出现过\(BG\),就一定要让这个\(R\)和它们匹配,否则就会使\(\sum a_i\)确定的情况下让\(\sum c_i\)变大
换而言之,如果出现过\(BG\)种的一种,那么我们必须匹配成\(RB\)或\(RG\),否则就会使\(\sum c_i\)确定的情况下让\(\sum a_i\)变小
否则单独拿出来,顺便统计答案即可
#include<cstdio>
#define RI register int
#define CI const int&
using namespace std;
const int N=300005,mod=998244353;
char s[N]; int n,ans,r,b,g,rb,rg,bg;
int main()
{
RI i; for (scanf("%d%s",&n,s+1),ans=i=1;i<=n;++i)
ans=1LL*ans*i%mod; for (i=3*n;i;--i)
switch (s[i])
{
case 'R':
if (bg) ans=1LL*ans*(bg--)%mod; else
if (b) ans=1LL*ans*(b--)%mod,++rb; else
if (g) ans=1LL*ans*(g--)%mod,++rg; else ++r;
break;
case 'G':
if (rb) ans=1LL*ans*(rb--)%mod; else
if (r) ans=1LL*ans*(r--)%mod,++rg; else
if (b) ans=1LL*ans*(b--)%mod,++bg; else ++g;
break;
case 'B':
if (rg) ans=1LL*ans*(rg--)%mod; else
if (r) ans=1LL*ans*(r--)%mod,++rb; else
if (g) ans=1LL*ans*(g--)%mod,++bg; else ++b;
break;
}
return printf("%d",ans),0;
}
C - Numbers on a Circle
首先这种操作这么神仙有可逆性的题目我们肯定要倒过来考虑,把加变成减
然后我们发现一个十分有趣的性质,当\(i\)能操作使\(i-1\)与\(i+1\)使不能操作的(因为一操作就变负了)
那么换句话说此时\(i\)操作减去的数不会再改变,因此操作多少次可以直接除一下
发现操作的顺序就是按照数的大小顺序操作的,因此我们把所有能操作的数扔进一个队列里,然后做完一个数考虑它两边的数能不能被操作即可
#include<cstdio>
#include<queue>
#define RI register int
#define CI const int&
using namespace std;
const int N=200005;
int n,a[N],b[N],pre[N],nxt[N]; long long ans; queue <int> q; bool vis[N];
inline bool check(CI id)
{
return b[id]-a[id]>=b[pre[id]]+b[nxt[id]];
}
int main()
{
RI i; for (scanf("%d",&n),i=1;i<=n;++i) scanf("%d",&a[i]);
for (i=1;i<=n;++i) scanf("%d",&b[i]),pre[i]=i-1,nxt[i]=i+1;
for (nxt[pre[1]=n]=i=1;i<=n;++i) if (check(i)) q.push(i),vis[i]=1;
while (!q.empty())
{
int nw=q.front(); vis[nw]=0; q.pop();
int cur=(b[nw]-a[nw])/(b[pre[nw]]+b[nxt[nw]]);
ans+=cur; b[nw]-=cur*(b[pre[nw]]+b[nxt[nw]]);
if (!vis[pre[nw]]&&check(pre[nw])) q.push(pre[nw]),vis[pre[nw]]=1;
if (!vis[nxt[nw]]&&check(nxt[nw])) q.push(nxt[nw]),vis[nxt[nw]]=1;
}
for (i=1;i<=n;++i) if (a[i]!=b[i]) return puts("-1"),0;
return printf("%lld",ans),0;
}
D - Sorting a Grid
我们考虑将输入看作一个\(n\times m\)的二元组\((x_i,y_i)\),来表示\(i\)这个数必须从第\(x_i\)行走的第\(y_i\)行,且它们需要被放置同一列
那么我们如果建出这样的二分图,把\(x_i\)向\(y_i\)连边,跑一个最大匹配,那此时的方案可以作为第一列的方案
然后考虑霍尔定理,我们发现此时每个点的度数都是\(M\),因此存在完美匹配
考虑每次找出一个匹配用来填某一列,然后删掉对应的边重复填即可
套路的不能再套路的题目
#include<cstdio>
#include<vector>
#include<cstring>
#include<iostream>
#include<assert.h>
#define RI register int
#define CI const int&
using namespace std;
const int N=205,M=100005,INF=1e9;
int n,m,a[N][N],fr[N*N],to[N*N],b[N][N],c[N][N],p[N]; vector <int> eg[N][N];
class Network_Flow
{
private:
struct edge
{
int to,nxt,v;
}e[M]; int head[N],cur[N],s,t,cnt,dep[N],q[N];
inline void addedge(CI x,CI y)
{
e[++cnt]=(edge){y,head[x],1}; head[x]=cnt;
e[++cnt]=(edge){x,head[y],0}; head[y]=cnt;
}
#define to e[i].to
inline bool BFS(CI s,CI t)
{
RI H=0,T=1; memset(dep,-1,t+1<<2); dep[q[1]=s]=0;
while (H<T)
{
int now=q[++H]; for (RI i=head[now];i;i=e[i].nxt)
if (e[i].v&&!~dep[to]) dep[to]=dep[now]+1,q[++T]=to;
}
return ~dep[t];
}
inline int DFS(CI now,CI t,int dis)
{
if (now==t) return dis; int ret=0;
for (RI& i=cur[now];i&&dis;i=e[i].nxt)
if (e[i].v&&dep[to]==dep[now]+1)
{
int dist=DFS(to,t,min(e[i].v,dis));
dis-=dist; ret+=dist; e[i].v-=dist; e[i^1].v+=dist;
}
if (!ret) dep[now]=0; return ret;
}
#undef to
public:
inline void init(void)
{
RI i,j; memset(head,0,(t=(n<<1|1))+1<<2); cnt=1;
for (i=1;i<=n;++i) addedge(s,i),addedge(n+i,t);
for (i=1;i<=n;++i) for (j=1;j<=n;++j)
if (!eg[i][j].empty()) addedge(i,n+j);
}
inline void Dinic(void)
{
int ret=0; while (BFS(s,t)) memcpy(cur,head,t+1<<2),ret+=DFS(s,t,INF);
assert(ret==n); for (RI i=1,j;i<=n;++i)
for (j=head[i];j;j=e[j].nxt) if (e[j].to!=s&&!e[j].v) p[i]=e[j].to-n;
}
}NF;
int main()
{
RI i,j,k; for (scanf("%d%d",&n,&m),i=1;i<=n;++i)
for (j=1;j<=m;++j) scanf("%d",&a[i][j]),fr[a[i][j]]=i;
for (i=1;i<=n;++i) for (j=1;j<=m;++j) to[(i-1)*m+j]=i;
for (i=1;i<=n*m;++i) eg[fr[i]][to[i]].push_back(i);
for (k=1;k<=m;++k) for (NF.init(),NF.Dinic(),i=1;i<=n;++i)
b[i][k]=c[p[i]][k]=eg[i][p[i]].back(),eg[i][p[i]].pop_back();
for (i=1;i<=n;++i) for (j=1;j<=m;++j) printf("%d%c",b[i][j]," \n"[j==m]);
for (i=1;i<=n;++i) for (j=1;j<=m;++j) printf("%d%c",c[i][j]," \n"[j==m]);
return 0;
}
E - Reversing and Concatenating
考虑分类讨论,其实这题的情况还是挺好分析的
首先为了让字典序最小,我们肯定考虑尽量复制原来字符串种字典序最小的字符
- 若字符串的最后一个字符为最小的,连续长度为\(L\),那么此时的开头字符为最小值的长度就是\(L\times 2^K\)
- 若字符串中间的一段最长的字符连续长度为\(L\),那么此时的开头字符为最小值的长度就是\(L\times 2^{K-1}\)
发现数据范围很小,我们直接暴枚从那个地方为结尾开始取即可,复杂度\(O(n^2)\)
#include<cstdio>
#include<iostream>
#define RI register int
#define CI const int&
using namespace std;
const int N=10005;
char s[N],mi='z',ans[N],tp[N]; int n,k;
inline bool cmp_min(char *a,char *b)
{
for (RI i=1;i<=n;++i)
if (a[i]!=b[i]) return a[i]<b[i]; return 0;
}
inline void solve(char *s,int k)
{
int nw=n,len=0; while (nw&&s[nw]==mi) --nw,++len;
while (k&&len<n) --k,len<<=1; len=min(n,len);
RI i; for (i=1;i<=len;++i) tp[i]=mi;
for (i=len+1;i<=n;++i) tp[i]=s[nw--];
if (cmp_min(tp,ans)) for (i=1;i<=n;++i) ans[i]=tp[i];
}
int main()
{
RI i; for (scanf("%d%d%s",&n,&k,s+1),i=1;i<=n;++i)
mi=min(s[i],mi),s[(n<<1)-i+1]=s[i],ans[i]='z';
if (s[n]==mi) solve(s,k);
for (i=n+1;i<=(n<<1);++i) if (s[i]==mi) solve(s+i-n,k-1);
return puts(ans+1),0;
}
F - Counting of Subarrays
我菜死了根本不会做,留着以后填坑,题解可以看曲明姐姐的
Postscript
哎呀比赛的坑可好歹是填完了,又要开新的坑了\kel
AtCoder Grand Contest 037的更多相关文章
- AtCoder Grand Contest 037题解
传送门 \(A\) 直接把每个字母作为一个字符串,如果某个串和它前面的相同,那么就把这个字母和它后面那个字母接起来.然而我并不会证明这个贪心的正确性 //quming #include<bits ...
- AtCoder Grand Contest 037 简要题解
从这里开始 题目目录 Problem A Dividing a String 猜想每段长度不超过2.然后dp即可. 考虑最后一个长度大于等于3的一段,如果划成$1 + 2$会和后面相同,那么划成$2 ...
- 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 翻译 有\( ...
- AtCoder Grand Contest 031 简要题解
AtCoder Grand Contest 031 Atcoder A - Colorful Subsequence description 求\(s\)中本质不同子序列的个数模\(10^9+7\). ...
- AtCoder Grand Contest 010
AtCoder Grand Contest 010 A - Addition 翻译 黑板上写了\(n\)个正整数,每次会擦去两个奇偶性相同的数,然后把他们的和写会到黑板上,问最终能否只剩下一个数. 题 ...
- AtCoder Grand Contest 009
AtCoder Grand Contest 009 A - Multiple Array 翻译 见洛谷 题解 从后往前考虑. #include<iostream> #include< ...
- AtCoder Grand Contest 008
AtCoder Grand Contest 008 A - Simple Calculator 翻译 有一个计算器,上面有一个显示按钮和两个其他的按钮.初始时,计算器上显示的数字是\(x\),现在想把 ...
- AtCoder Grand Contest 007
AtCoder Grand Contest 007 A - Shik and Stone 翻译 见洛谷 题解 傻逼玩意 #include<cstdio> int n,m,tot;char ...
随机推荐
- WPF 精修篇 全局为处理异常处理
原文:WPF 精修篇 全局为处理异常处理 当我们写代码的时候 对代码错误异常处理 有的时候会 没做处理 比如 我们执行如下代码 会引发程序崩溃 private void Button_Click(ob ...
- WIN10X64LTSC2019中度精简版by双心
WIN10X64LTSC2019中度精简版by双心https://www.cnblogs.com/liuzhaoyzz/p/11295032.html 一.前言:关于LTSC中度精简版的说明 一个MM ...
- 大话设计模式Python实现-桥接模式
桥接模式(Bridge Pattern):将抽象部分与它的实现部分分离,使它们都可以独立地变化. 下面是一个桥接模式的demo: #!/usr/bin/env python # -*- coding: ...
- zabbix 监控项报"Value "(No info could be read for "-p": geteuid()=1002 but you should be root"
zabbix 监控项报错如下: “Value "(No info could be read for "-p": geteuid()=1002 but you shoul ...
- 错误InnoDB:Attemptedtoopenapreviouslyopenedtablespace.
2013-08-04 13:48:22 760 [ERROR] InnoDB: Attempted to open a previously opened tablespace. Previous t ...
- NumPy 学习 第二篇:索引和切片
数组索引是指使用中括号 [] 来定位数据元素,不仅可以定位到单个元素,也可以定位到多个元素.索引基于0,并接受从数组末尾开始索引的负索引. 举个例子,正向索引从0开始,从数组开始向末尾依次加1递增:负 ...
- Flask 教程 第一章:Hello, World!
本文翻译自The Flask Mega-Tutorial Part I: Hello, World! 一趟愉快的学习之旅即将开始,跟随它你将学会用Python和Flask来创建Web应用.上面的视频包 ...
- Java生鲜电商平台-深入订单拆单架构与实战
Java生鲜电商平台-深入订单拆单架构与实战 Java生鲜电商中在做拆单的需求,细思极恐,思考越深入,就会发现里面涉及的东西越来越多,要想做好订单拆单的功能,还是相当有难度, 因此总结了一下拆单功能细 ...
- SpringBoot(九)RabbitMQ安装及配置和使用,消息确认机制
Windows下RabbitMQ安装及配置地址: https://blog.csdn.net/zhm3023/article/details/82217222RabbitMQ(四)订阅模式:https ...
- vue-cli3和element做一个简单的登陆页面
1.先用vue-cli3创建一个项目 2.安装element模块 全局安装 npm i element-ui -S 3在main.js引入模块 import ElementUI from 'eleme ...