1103模拟赛
1103 模拟赛
忍不了!一拳把疫情打爆。我要回家!我要回家!我要回家!
Codeforces Subsequences · 改
题意
\(~~~~\) 求一个最短的字符串,使得其至少有 \(k\) 个
iamhuman
的子序列。
\(~~~~\) \(1\leq k\leq 10^16\).
题解
\(~~~~\) 你永远不知道一个人可以在这题怎么挂分(有读题读成恰好自闭了的,有英文写了个iamhumam
的···)
\(~~~~\) 先考虑从一个开始往上加,显然我们会构造若干个 i
,若干个 a
,\(\dots\) ,若干个 n
,所以考虑从 \(x\) 个某个字符变成 \(x+1\) 个,那子序列就会变成 \(now\times \frac{x+1}{x}\) 个。显然可以感觉到 \(x\) 越小那增长越快,所以我们把每个字符均匀增长即可。
代码
查看代码
#include <bits/stdc++.h>
#define ll long long
using namespace std;
template<typename T>void read(T &x)
{
T f=1;x=0;char s=getchar();
while(s<'0'||s>'9'){if(s=='-')f=-1;s=getchar();}
while(s>='0'&&s<='9') {x=x*10+s-'0';s=getchar();}
x*=f;
}
char To[10];
int res[10];
int main() {
// freopen("iamhuman.in","r",stdin);
// freopen("iamhuman.out","w",stdout);
ll k;read(k);
for(int i=1;i<=8;i++) res[i]=1;
To[1]='i'; To[2]='a'; To[3]='m'; To[4]='h';
To[5]='u'; To[6]='m'; To[7]='a'; To[8]='n';
ll now=1,Num=2;
while(now<k)
{
for(int i=1;i<=8;i++)
{
res[i]++;
now=now*Num/(Num-1);
if(now>=k) break;
}
Num++;
}
for(int i=1;i<=8;i++)
for(int j=1;j<=res[i];j++) putchar(To[i]);
return 0;
}
CF1368C Even Picture·加强
题意
\(~~~~\) 求一个
.
和 \(900\) 个以内的#
组成的任意大小字符画,要求所有#
连通,任何#
周边只有 \(2\) 或 \(4\) 个#
且恰好有 \(n\) 个#
周边有 \(4\) 个#
。
\(~~~~\) \(1\leq n\leq 300\).
题解
\(~~~~\) 构造一个非常密集的堆放肯定是很优秀的想法,我们先钦定堆放一行的 #
为有 \(4\) 个 #
相连的那种。然后把周围补齐,发现有 \(3\) 个相邻的那就钦定为 \(4\) 个相连继续构造,这样会得到下面两种可能:
...##......#...
..####....###..
.######..#####.
..####....###..
...##......#...
\(~~~~\) 第一种只有左右不合法,第二种上下左右都不合法,而我们可以用一条路径来连通左右不合法的情况。但是上下左右均不合法的情况就连起来很浪费,所以我们只考虑左右合法。
\(~~~~\) 更进一步地,我们发现这种东西可以串联起来再连路径:
...........##....
....##....####...
...####..######..
.################
.#.####..######.#
.#..##....####..#
.#.........##...#
.################
\(~~~~\) 然后发现这样写一发 \(n=300\) 只需要 \(400\) 多个 #
,恭喜踩掉标程!
Ciel and Flipboard
题意
\(~~~~\) 大小 \(n\times n\) 的矩形(\(n\) 为奇数),每次可以翻转 \(m\times m\) 范围内的数,其中 \(m=\frac{n+1}{2}\),求最终矩形内所有数和的最大值。
\(~~~~\) \(1\leq n\leq 33\).
题解
\(~~~~\) 发现结论:记 \(f(x,y)\) 表示 \(a_{x,y}\) 是否被翻转,那么: \(f(x,y) \oplus f(x,m) \oplus f(x,y+m)=0\) , \(f(x,y) \oplus f(m,y) \oplus f(x+m,y)=0\) ,发现这个结论似乎更难一些。证明反而非常简单。
\(~~~~\) 而且更进一步我们会发现只要满足这个条件就是合法的方案。因此你还会发现这个矩形内所有的 \(f(x,y)\) 都是互相独立的。
\(~~~~\) 对于 \((x,y)(x<m,y<m)\) 而言,它的对称点取决于 \((x,m)\) 和 \((m,y)\),所以我们只需要枚举 \((x,m)\) 和 \((m,y)\) 的翻转情况。
\(~~~~\) 但是上文已经提到了它们的决策是独立的,所以事实上只需要枚举 \((x,m)\) 的情况然后在此条件下计算 \((m,y)\) 的最有优决策即可。
代码
查看代码
#include <bits/stdc++.h>
#define ll long long
using namespace std;
template<typename T>void read(T &x)
{
T f=1;x=0;char s=getchar();
while(s<'0'||s>'9'){if(s=='-')f=-1;s=getchar();}
while(s>='0'&&s<='9') {x=x*10+s-'0';s=getchar();}
x*=f;
}
ll n,m;
ll arr[35][35],Rev[35][35];
ll F(ll x,ll y){return Rev[x][y]?-arr[x][y]:arr[x][y];}
ll Query(ll x,ll y,ll d)
{
ll res=0; Rev[x][y]=d; Rev[x+m][y]=Rev[m][y]^d;
Rev[x][y+m]=Rev[x][m]^d;
Rev[x+m][y+m]=Rev[m][y+m]^Rev[x][y+m];
return F(x,y)+F(x+m,y)+F(x,y+m)+F(x+m,y+m);
}
ll Query(ll y,ll d)
{
ll res=0; Rev[m][y]=d; Rev[m][y+m]=Rev[m][m]^d;
res+=F(m,y)+F(m,y+m);
for(ll x=1;x<m;x++) res+=max(Query(x,y,0),Query(x,y,1));
return res;
}
ll Calc()
{
ll res=0;
for(ll i=1;i<=n;i++) res+=F(i,m);
for(ll i=1;i<m;i++) res+=max(Query(i,0),Query(i,1));
return res;
}
int main() {
#ifndef ONLINE_JUDGE
freopen("input","r",stdin);
freopen("output","w",stdout);
#endif
read(n);m=(n+1)/2;
for(ll i=1;i<=n;i++)
for(ll j=1;j<=n;j++) read(arr[i][j]);
ll Ans=0;
for(ll S=0;S<(1<<m);S++)
{
for(ll i=1;i<=m;i++) Rev[i][m]=(S>>(i-1))&1;
for(ll i=1;i<m;i++) Rev[i+m][m]=Rev[m][m]^Rev[i][m];
Ans=max(Ans,Calc());
}
printf("%lld",Ans);
return 0;
}
/*
清夜无尘。月色如银。酒斟时、须满十分。浮名浮利,虚苦劳神。叹隙中驹,石中火,梦中身。
虽抱文章,开口谁亲。且陶陶、乐尽天真。几时归去,作个闲人。对一张琴,一壶酒,一溪云。
*/
Shifting Dominoes
题意
\(~~~~\) 若干多米诺骨牌横向或竖向放置,取出其中一块,将其他的任意沿长边移动。求最后两个空格位置有哪些可能。
\(~~~~\) \(1\leq nm\leq 2\times 10^5\).
题解
\(~~~~\) 考虑用这种类型的常见套路,建图的时候考虑空格可以移动到哪些地方,你就建出了一张图。并且黑和白格子之间是互不影响的。
\(~~~~\) 那么我们来找一下图的一些性质,比如说:这张图是没有环的。因为如果这张图有环那空位必定可以转一圈转回原位,但是显然空位原来的位置已经被占了,所以原图没有环。
\(~~~~\) 而且,每个点的入度最多为 \(1\)。因此原图形成的是一棵树。(准确来说,是两棵)
\(~~~~\) 黑白染色的两种格子互不影响,所以合法方案即可以选出一个骨牌,它的两个原先的位置在树上均为该方案对应点的祖先。
\(~~~~\) 所以我们可以把两棵树上的 dfn 序放到二维平面上,那么这其实就是一个矩形求交问题,扫描线求解即可。
代码
查看代码
#include <bits/stdc++.h>
#define ll long long
#define PII pair<int,int>
#define mp(a,b) make_pair(a,b)
using namespace std;
template<typename T>void read(T &x)
{
T f=1;x=0;char s=getchar();
while(s<'0'||s>'9'){if(s=='-')f=-1;s=getchar();}
while(s>='0'&&s<='9') {x=x*10+s-'0';s=getchar();}
x*=f;
}
int n,m,cnt=0;
bool NotRt[200005];
vector <int> G[200005];
char Str[200005],S[200005];
int id[200005],dfn[200005],Times,siz[200005];
inline int ID(int x,int y){return (x-1)*m+y;}
void dfs(int u,int fa)
{
dfn[u]=++Times,siz[u]=1;
for(int i=0;i<G[u].size();i++)
{
int v=G[u][i];
if(v==fa) continue;
dfs(v,u); siz[u]+=siz[v];
}
}
int brr[200005],Cnt;
struct Ask{
int x,Y1,Y2,Val;
Ask(){}
Ask(int X,int YY1,int YY2,int VAL){x=X,Y1=YY1,Y2=YY2,Val=VAL;}
}A[200005];
vector<PII>Domi[200005];
bool cmp(Ask x,Ask y){return x.x<y.x;}
struct SegmentTree{
#define ls p<<1
#define rs p<<1|1
#define lson p<<1,l,mid
#define rson p<<1|1,mid,r
int Len[1600005],Times[1600005];
void pushUp(int p,int l,int r)
{
if(Times[p]) Len[p]=brr[r]-brr[l];
else if(l+1==r) Len[p]=0;
else Len[p]=Len[ls]+Len[rs];
}
void Modify(int p,int l,int r,int lx,int rx,int Val)
{
if(lx<=l&&r<=rx)
{
Times[p]+=Val;
// cerr<<"Modify:"<<p<<" "<<Times[p]<<endl;
pushUp(p,l,r);
return;
}
if(l+1==r) return;
int mid=(l+r)>>1;
if(lx<=mid) Modify(lson,lx,rx,Val);
if(mid<rx) Modify(rson,lx,rx,Val);
pushUp(p,l,r);
}
#undef ls
#undef rs
#undef lson
#undef rson
}Seg;
int main() {
#ifndef ONLINE_JUDGE
freopen("input","r",stdin);
freopen("output","w",stdout);
#endif
read(n);read(m);
for(int i=1;i<=n;i++)
{
scanf("%s",Str+1);
for(int j=1;j<=m;j++) S[++cnt]=Str[j];
}
int tot=0;
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
{
if(i<=n-2&&S[ID(i+1,j)]=='U') G[ID(i,j)].push_back(ID(i+2,j)),NotRt[ID(i+2,j)]=true;
if(i>=3 &&S[ID(i-1,j)]=='D') G[ID(i,j)].push_back(ID(i-2,j)),NotRt[ID(i-2,j)]=true;
if(j<=m-2&&S[ID(i,j+1)]=='L') G[ID(i,j)].push_back(ID(i,j+2)),NotRt[ID(i,j+2)]=true;
if(j>=3 &&S[ID(i,j-1)]=='R') G[ID(i,j)].push_back(ID(i,j-2)),NotRt[ID(i,j-2)]=true;
if(!id[ID(i,j)])
{
id[ID(i,j)]=++tot;
if(S[ID(i,j)]=='U') id[ID(i+1,j)]=tot;
if(S[ID(i,j)]=='L') id[ID(i,j+1)]=tot;
}
Domi[id[ID(i,j)]].push_back(mp(i,j));
}
}
for(int i=1;i<=n*m;i++) if(!NotRt[i]) dfs(i,0);
int q=0;
for(int i=1;i<=tot;i++)
{
int X1=Domi[i][0].first,Y1=Domi[i][0].second,X2=Domi[i][1].first,Y2=Domi[i][1].second;
// cerr<<X1<<" "<<Y1<<" "<<X2<<" "<<Y2<<endl;
int x=ID(X1,Y1),y=ID(X2,Y2);
int L1=dfn[x],R1=dfn[x]+siz[x]-1;
int L2=dfn[y],R2=dfn[y]+siz[y]-1;
if((X1+Y1)&1) swap(L1,L2),swap(R1,R2);
A[++q]=Ask(L1,L2,R2+1,1);
A[++q]=Ask(R1+1,L2,R2+1,-1);
brr[++Cnt]=L2; brr[++Cnt]=R2+1;
}
sort(brr+1,brr+1+Cnt); Cnt=unique(brr+1,brr+1+Cnt)-brr-1;
sort(A+1,A+1+q,cmp);
ll Ans=0;
for(int i=1;i<=q;i++)
{
Ans+=Seg.Len[1]*(A[i].x-A[i-1].x);
// cerr<<Seg.Len[1]<<" "<<A[i].x-A[i-1].x<<endl;
A[i].Y1=lower_bound(brr+1,brr+1+Cnt,A[i].Y1)-brr;
A[i].Y2=lower_bound(brr+1,brr+1+Cnt,A[i].Y2)-brr;
// cerr<<A[i].Y1<<" "<<A[i].Y2<<" "<<A[i].Val<<" "<<Cnt<<endl;
Seg.Modify(1,1,Cnt,A[i].Y1,A[i].Y2,A[i].Val);
}
printf("%lld",Ans);
return 0;
}
/*
清夜无尘。月色如银。酒斟时、须满十分。浮名浮利,虚苦劳神。叹隙中驹,石中火,梦中身。
虽抱文章,开口谁亲。且陶陶、乐尽天真。几时归去,作个闲人。对一张琴,一壶酒,一溪云。
*/