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;
}
/*
清夜无尘。月色如银。酒斟时、须满十分。浮名浮利,虚苦劳神。叹隙中驹,石中火,梦中身。
虽抱文章,开口谁亲。且陶陶、乐尽天真。几时归去,作个闲人。对一张琴,一壶酒,一溪云。
*/
posted @ 2022-11-03 21:29  Azazеl  阅读(49)  评论(0)    收藏  举报