AGC056 简要题解
A. Three Cells per Row and Column
个人认为 AGC 题的评分普遍都偏低,大概是打 AGC 的人都太强了吧。
每行放 \(3\) 个,我们希望每行都有 \(1\) 的贡献,我们不妨假设第 \(i\) 行恰好贡献在 \(i\) 上。
基于以上的猜测我们有如下构造:
#.##.......
.#.##......
..#.##.....
...#.##....
大概是这样,不过这样右边多出一条,并且最后三行有点问题,调整一下即可。
具体就是在倒数第三行把右边合起来,并在最后两行填好前两列的空缺并造出两个连通块。
比如在 \(6\) 时,构造长这样:
#.##..
.#.##.
..#.##
...###
##....
###..#
点击查看代码
#include<bits/stdc++.h>
using namespace std;
const int maxn=2e5+10;
const int mod=1e9+7;
#define inf 1e9
inline int read(){
int x=0,f=1;char c=getchar();
while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
while(c>='0'&&c<='9'){x=(x<<1)+(x<<3)+c-'0';c=getchar();}
return x*f;
}
char C[505][505];
int n,m;
int main(){
n=read();
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)C[i][j]='.';
for(int i=1;i<=n-3;i++)
C[i][i]=C[i][i+2]=C[i][i+3]='#';
C[n-2][n-2]=C[n-2][n-1]=C[n-2][n]='#';
C[n-1][1]=C[n-1][2]=C[n-1][3]='#';
C[n][1]=C[n][2]=C[n][n]='#';
for(int i=1;i<=n;i++,puts(""))
for(int j=1;j<=n;j++)putchar(C[i][j]);
return 0;
}
B. Range Argmax
你看这个题这个数据范围,一看就是区间 \(dp\),然后枚举最大值划分。但是无限算重,寄。
这个我为啥不会,感觉我应该很会这种的,大概是脑子缺氧了。
我们希望对生成序列相同的当中字典序最小的计数,也就是说,我们对最大值尽量靠前的计数。
也就是说,对于区间 \([l,r]\) 若最大值位于 \(k\),则 \([k+1,r]\) 不重要了,但是 \([l,k-1]\) 中的最大值必须存在一个区间在 \([l,r]\) 且包含它们,否则可以交换。
设 \(dp_{l,r,k}\) 表示在区间 \([l,r]\) 内且最大值的位置不小于 \(k\) 的方案数,\(S_{l,r,k}\) 表示区间 \([l,r]\) 的最大值位于 \(k\) 时左部最大值最前能摆放的位置。
则 \(dp_{l,r,k}=dp_{l,r,k+1}+dp_{l,k-1,S_{l,r,k}}dp_{k+1,r,k+1}\)。
点击查看代码
#include<bits/stdc++.h>
using namespace std;
const int maxn=2e5+10;
const int mod=998244353;
#define inf 1e9
inline int read(){
int x=0,f=1;char c=getchar();
while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
while(c>='0'&&c<='9'){x=(x<<1)+(x<<3)+c-'0';c=getchar();}
return x*f;
}
const int N=505;
int n,m,F[N][N][N],S[N][N][N];
int main(){
n=read(),m=read();
memset(S,0x3f,sizeof(S));
for(int i=1,l,r;i<=m;i++){
l=read(),r=read();
for(int j=l;j<=r;j++)
S[l][r][j]=min(S[l][r][j],l);
}for(int i=n;i;--i)
for(int j=i+1;j<=n;j++)
for(int k=i;k<=j;k++)
S[i][j][k]=min(S[i][j][k],min(j+1,min(S[i+1][j][k],S[i][j-1][k])));
for(int i=1;i<=n;i++)F[i][i][i]=1;
for(int i=1;i<=n+1;i++)
for(int j=1;j<=n+1;j++)F[i][i-1][j]=1;
for(int i=n;i;--i)
for(int j=i+1;j<=n;j++)
for(int k=j;k>=i;k--)
F[i][j][k]=(F[i][j][k+1]+1ll*F[i][k-1][S[i][j][k]]*F[k+1][j][k+1])%mod;
printf("%d\n",F[1][n][1]);
return 0;
}
C. 01 Balanced
这种题除了逐位确定我想不到别的方法,然后就没有然后了。到目前为止只会 A 题是怎么回事/ll
好吧,我也搞不明白,但反正就是差分约束就是了。期待一个好心哥哥给我讲解捏~
点击查看代码
#include<bits/stdc++.h>
using namespace std;
const int maxn=1e6+10;
const int mod=1e9+7;
#define inf 1e9
inline int read(){
int x=0,f=1;char c=getchar();
while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
while(c>='0'&&c<='9'){x=(x<<1)+(x<<3)+c-'0';c=getchar();}
return x*f;
}
int n,m,dis[maxn],vis[maxn];
vector<int>G[maxn];
#define pb push_back
deque<int>Q;
int main(){
n=read(),m=read();Q.push_front(0);
for(int i=1;i<=n;i++)dis[i]=inf;
for(int i=1,l,r;i<=m;i++)
l=read()-1,r=read(),G[l].pb(r),G[r].pb(l);
while(!Q.empty()){
int x=Q.front();Q.pop_front();
for(auto t:G[x])if(dis[t]>dis[x])
dis[t]=dis[x],Q.push_front(t);
if(x&&dis[x-1]>dis[x]+1)
dis[x-1]=dis[x]+1,Q.push_back(x-1);
if(x<n&&dis[x+1]>dis[x]+1)
dis[x+1]=dis[x]+1,Q.push_back(x+1);
}for(int i=1;i<=n;i++)
putchar(dis[i]>dis[i-1]?'0':'1');
return 0;
}