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的更多相关文章

  1. AtCoder Grand Contest 037题解

    传送门 \(A\) 直接把每个字母作为一个字符串,如果某个串和它前面的相同,那么就把这个字母和它后面那个字母接起来.然而我并不会证明这个贪心的正确性 //quming #include<bits ...

  2. AtCoder Grand Contest 037 简要题解

    从这里开始 题目目录 Problem A Dividing a String 猜想每段长度不超过2.然后dp即可. 考虑最后一个长度大于等于3的一段,如果划成$1 + 2$会和后面相同,那么划成$2 ...

  3. AtCoder Grand Contest 012

    AtCoder Grand Contest 012 A - AtCoder Group Contest 翻译 有\(3n\)个人,每一个人有一个强大值(看我的假翻译),每三个人可以分成一组,一组的强大 ...

  4. AtCoder Grand Contest 011

    AtCoder Grand Contest 011 upd:这篇咕了好久,前面几题是三周以前写的... AtCoder Grand Contest 011 A - Airport Bus 翻译 有\( ...

  5. AtCoder Grand Contest 031 简要题解

    AtCoder Grand Contest 031 Atcoder A - Colorful Subsequence description 求\(s\)中本质不同子序列的个数模\(10^9+7\). ...

  6. AtCoder Grand Contest 010

    AtCoder Grand Contest 010 A - Addition 翻译 黑板上写了\(n\)个正整数,每次会擦去两个奇偶性相同的数,然后把他们的和写会到黑板上,问最终能否只剩下一个数. 题 ...

  7. AtCoder Grand Contest 009

    AtCoder Grand Contest 009 A - Multiple Array 翻译 见洛谷 题解 从后往前考虑. #include<iostream> #include< ...

  8. AtCoder Grand Contest 008

    AtCoder Grand Contest 008 A - Simple Calculator 翻译 有一个计算器,上面有一个显示按钮和两个其他的按钮.初始时,计算器上显示的数字是\(x\),现在想把 ...

  9. AtCoder Grand Contest 007

    AtCoder Grand Contest 007 A - Shik and Stone 翻译 见洛谷 题解 傻逼玩意 #include<cstdio> int n,m,tot;char ...

随机推荐

  1. WPF 精修篇 用户控件

    原文:WPF 精修篇 用户控件 增加用户控件 数据绑定还是用依赖属性 使用的事件 就委托注册一下 public delegate void ButtonClick(object b,EventArgs ...

  2. Repair Microsoft.VisualStudio.MinShell.Msi.Resources 2203 error And visual studio 2019 key

    1. Go to the properties of "My computer" 2. Go to advanced settings of the system 3. Go to ...

  3. networkx生成网络

    ER随机网络,WS小世界网络,BA无标度网络的生成 import networkx as nx import matplotlib.pyplot as plt #ER随机网络 #10个节点,连接概率为 ...

  4. Python与用户交互

    目录 一.为什么交互? 二.如何交互? 三.Python2的交互 一.为什么交互?   让我们来回顾计算机的发明有何意义,计算机的发明是为了奴役计算机,解放劳动力.假设我们现在写了一个ATM系统取代了 ...

  5. php精确计算

    php BC高精确度函数库 结果: php一般的取余 只是除以整数 bc精度取余 精确到了小数

  6. git 添加add readme.txt 报fatal: pathspec 'readme.txt' did not match any files错误

    刚刚接触git版本管理器,跟着廖雪峰老师的git教程学习,在创建一个新的文件时,使用的是$ git add readme.txt指令,但是报出fatal: pathspec 'readme.txt' ...

  7. Java实现编辑距离算法

    Java实现编辑距离算法 编辑距离,又称Levenshtein距离(莱文斯坦距离也叫做Edit Distance),是指两个字串之间,由一个转成另一个所需的最少编辑操作次数,如果它们的距离越大,说明它 ...

  8. pytest框架优化——清理历史截图图片和allure报告文件

    痛点分析: 当我们每次执行完用例的时候,如果出现bug或者是测试脚本出了问题,一般会通过测试报告.异常截图.日志来定位分析,但是我们发现运行次数多了之后,异常截图和测试报告会不停地增多,对我们定位分析 ...

  9. 多线程通信的两种方式? (可重入锁ReentrantLock和Object)

    (一)Java中线程协作的最常见的两种方式: (1)利用Object的wait().notify()和notifyAll()方法及synchronized (2)使用Condition.Reentra ...

  10. 关于Maven+Tomcat7下cannot be cast to javax.servlet.Servlet问题的解决办法

    今天在开发 JavaWeb 项目的时候,遇到了这么一个问题,这个错误是我在进行表单的异步提交的时候出现的.无法转化为 Servlet 经过我的一番检查之后!没有发现任何问题.... 注解配置无误 继承 ...