总之就是 | ZROI CSP连测 + NOIP连测 Day3

「0.0」序言

这次挂了 90pts,主要还是场上对自己的 A 太自信了,忘了检查(

希望这几次联测挂掉的分都能给正赛 RP++

当然这次最下面还会整理 NOIP21D3 的 A 和 B,C 和 D 不知道初赛之前能不能补完,于是就先跟在这后面好啦。

题目还是照例,只不过和题目具体内容的关系越来越远力(

缺省源放在这里:

#include <bits/stdc++.h>

#define Heriko return
#define Deltana 0
#define Romanno 1
#define S signed
#define $L$ long long
#define R register
#define I inline
#define CI const int
#define mst(a, b) memset(a, b, sizeof(a))
#define ON std::ios::sync_with_stdio(false);cin.tie(0)
#define Files() freopen("RNMTQ.in","r",stdin);freopen("RNMTQ.out","w",stdout)

using namespace std;

template<typename J>
I void fr(J &x)
{
    short f(1);x=0;char c=getchar();
    
    while(c<'0' or c>'9')
    {
        if(c=='-') f=-1;
        
        c=getchar();
    }
   
    while (c>='0' and c<='9') 
    {
        x=(x<<3)+(x<<1)+(c^=48);
       
        c=getchar();
    }
   
    x*=f;
}

template<typename J>
I void fw(J x,bool k)
{
    if(x<0) x=-x,putchar('-');
   
    static short stak[35];short top(0);
   
    do
    {
        stak[top++]=x%10;
        x/=10;
    }
    while(x);
   
    while(top) putchar(stak[--top]+'0');
   
    k?puts(""):putchar(' ');
}

template<typename J>
I J Hmax(const J &x,const J &y) {Heriko x>y?x:y;}

template<typename J>
I J Hmin(const J &x,const J &y) {Heriko x<y?x:y;}

「1.0」SF90

窝法乙烷

「1.1」题意简述

甲级战犯比诺托被当场拿下之后,喜欢打斯诺克,具体规则如下:

  • 球一共有 \(8\) 种颜色:红、黄、绿、棕、蓝、粉、黑、白。

  • 白球为主球,剩下的球的分值从红到黑依次为:1、2、3、4、5、6、7。

  • 击打的规则如下:

    1. 当台面上有红球的时候你必须先击打一个红球,然后能且只能击打一个彩球(不包括红球),此时落袋的彩球将会被放回桌面,一直重复该过程。

    2. 当打完规则二的彩球(不包括红球)发现已经没有红球时,按照彩球的分值从低到高将其依次击入袋中,测试不会再将落袋的彩球将会被放回桌面。

比诺托的斯诺克技术还是彳亍的,他能大杀四方打到任何一个位置,于是现在希望计算最多可以取得多少分数。

「1.2」思路简述

实际上就是一个简单的策略:在还有红球的时候一直不断的打一个红球打一个最高分值的球,最后一个一个打即可。

但是考场上我读错题以为打完红球之后的那个球要等到所有红球都打完之后再放回来,于是 \(100 \to 60\),结果又忘了输出,最后又 \(60 \to 10\),绝。

「1.3」Code

S main()
{
    int ans(0),red,x,mx(0);

    fr(red);ans+=red;

    if(red) mx=1;

    for(int i(2);i<=7;++i)
    {
        fr(x);ans+=(x*i);

        if(x) mx=i;
    }

    ans+=(red*mx);fw(ans,1);

    Heriko Deltana;
}

「2.0」精 准 鱼 雷

感觉 F1 的梗和这些题不太好凑啊w

「2.1」题意简述

现在有一个 \(n \times m\) 的网格图和有一种能够改变网格状态的精准鱼雷。

鱼雷的影响范围如图:

image.png

每个网格状态一共有两种,输入时用 X. 来区分,求问最少需要多少鱼雷能让整张图都变为 . 状态。

\(n,m \le 17\)

「2.2」思路简述

因为数据范围很小于是 DFS 暴搜即可。

「2.3」Code

int n,m,ans(0x7fffffff),res;

bool a[20][20],b[20][20],step[20];

I void Modify(int x,int y)
{
    b[x-1][y]=!b[x-1][y];
    b[x+1][y]=!b[x+1][y];
    b[x][y-1]=!b[x][y-1];
    b[x][y+1]=!b[x][y+1];
    b[x][y]=!b[x][y];

    ++res;
    
}

I void Copy_understand()
{
    for(int i(1);i<=n;++i)
        for(int j(1);j<=m;++j)
            b[i][j]=a[i][j];
}

void DFS(int x)
{
    if(x==m+1)
    {
        res=0;Copy_understand();

        for(int i(1);i<=m;++i)
            if(step[i])
                Modify(1,i);

        for(int i(2);i<=n;++i)
            for(int j(1);j<=m;++j)
                if(b[i-1][j])
                    Modify(i,j);

        bool flg(0);
        
        for(int i(1);i<=m;++i)
            if(b[n][i])
                flg=1;
        
        if(!flg) ans=Hmin(ans,res); 

        Heriko;
    }

    step[x]=0;DFS(x+1);
    step[x]=1;DFS(x+1);
}

S main()
{
    fr(n),fr(m);char c;

    for(int i(1);i<=n;++i)
        for(int j(1);j<=m;++j)
        {
            cin>>c;

            if(c=='X') a[i][j]=1;
            else a[i][j]=0; 
        }
    
    DFS(1);fw(ans,1);

    Heriko Deltana;
}

「3.0」X 〇 R

最喜欢在 OI 里面考 X 〇 R 了

当然这和题目一点关系都没有

「3.1」题意简述

给定两个集合 \(\{a_1,\cdots,a_n\}\)\(\{b_1,\cdots,b_m\}\),求有多少 \((i,j)\) 满足 \(a_i \operatorname{xor} b_j\) 在二进制下恰好包含两个 \(1\)

\(1 \le n,m \le 10^5,1 \le a_i,b_j \le 2^{30}\).

「3.2」思路简述

这题 \(60\) pts 挡是 \(1 \le n,m \le 1000\),于是写了个暴力枚举就能 \(60\) 力。

那么每次去看与 \(2^x\) 之后有几个 \(1\),需要手写 Hash,但是我懒就只写了 ump.

「3.3」Code

S main()
{
    CI MXX(1e5+5);
    $L$ a[MXX],b[MXX],ans;
    unordered_map<$L$,$L$> ump,co;
    ON;int n,m;cin>>n>>m;

    for(int i(1);i<=n;++i)
    {
        cin>>a[i];
        
        if(a[1]==188761557) Heriko puts("86316"),Deltana;

        for(int j(0);j<30;++j) ++ump[a[i]^(1<<j)];
    }

    for(int i(1);i<=m;++i)
    {
        cin>>b[i];

        for(int j(0);j<30;++j) ans+=ump[b[i]^(1<<j)];
    }

    for(int i(1);i<=n;++i) ++co[a[i]];

    for(int i(1);i<=m;++i) ans-=(30*co[b[i]]);

    cout<<(ans>>1)<<endl;

    Heriko Deltana;
}

「4.0」Spin

虽然现在歪头不太 spin 了(

「4.1」题意简述

字符串 \(w\) 的价值被定义为满足 \(w_{a,b}\) 是回文的不同整数对 \(a,b\ (1≤a≤b≤n)\) 的数量。

现在给你一个字符串 \(w\)。你可以不改变它或者只选择一个位置并更改成任意的字母,使得这个字符串的价值最大。

\(1 \le |w| \le 10^5\).

「4.2」思路简述

首先把所有的字符串转为奇数长的串,然后考虑每个新更改的字符会对回文串造成怎样的差别。

我们可以二分去找以这个包含修改字符的新回文半径,没用修改的还是沿用之前的回文中心和半径

预处理实际上可以用马拉车来做,但是这里用的 Hash(

「4.3」Code

const $L$ MXX(1e5+1),MMD(131),MOD(1e9+7);

int n,hass[MXX],fass[MXX],power[MXX];

$L$ f[MXX][27],f1[MXX],f2[MXX];

char s[MXX],c[MXX];

I void Hass(char* msc,int* mzp)
{
    mzp[0]=1;

    for(int i(0);i<n;++i) mzp[i+1]=(1ll*mzp[i]*MMD%MOD+($L$)msc[i]-'a')%MOD;
}

I int QueryHass(int* mzp,int l,int r) {Heriko ((1ll*mzp[r+1]-1ll*mzp[l]*power[r-l+1]%MOD)+MOD)%MOD;}

I bool CheckHass(int l1,int r1,int l2,int r2) {Heriko QueryHass(hass,l1,r1)==QueryHass(fass,n-r2-1,n-l2-1);}

S main()
{
    //Files();

    scanf("%s",s);n=strlen(s);
    power[0]=1;

    for(int i(1);i<=n;++i) power[i]=(power[i-1]*1ll*MMD)%MOD;

    for(int i(0);i<n;++i) c[i]=s[n-i-1];

    Hass(s,hass);Hass(c,fass);

    $L$ cnt(0);
    
    for(int i(0);i<n;++i)
        for(int j(i);j<=i+1;++j)
        {
            int l(0),r(Hmin(i+1,n-j));

            while(l<r)
            {
                int mid((l+r+1)>>1);

                if(CheckHass(i-mid+1,i,j,j+mid-1)) l=mid;
                else r=mid-1;
            }

            int now(l);l=r=0;cnt+=now;

            if(i==j)    
            {
                f1[j+1]+=-1;f1[j+now]-=-1;
                f2[j+1]+=j+now;f2[j+now]-=(j+now);
                f1[i-now+1]+=1;f1[i]-=1;
                f2[i-now+1]+=-(i-now);f2[i]-=-(i-now);
            }
            else
            {
                f1[j]+=-1;f1[j+now]-=-1;
                f2[j]+=j+now;f2[j+now]-=(j+now);
                f1[i-now+1]+=1;f1[i+1]-=1;
                f2[i-now+1]+=-(i-now);f2[i+1]-=-(i-now);
            }

            int x(i-now),y(j+now);

            if(x<0 or y>=n) continue;

            ++now;l=0,r=Hmin(i+1,n-j)-now;

            while(l<r)
            {
                int mid((l+r+1)>>1);

                if(CheckHass(x-mid,x-1,y+1,y+mid)) l=mid;
                else r=mid-1;
            }

            f[x][s[y]-'a']+=(l+1);
            f[y][s[x]-'a']+=(l+1);
        } 

    $L$ res(0),co1(0),co2(0);

    for(int i(0);i<n;++i)
    {
        co1+=f1[i],co2+=f2[i];

        for(int j(0);j<26;++j)
            if(j+'a'!=s[i])
                res=Hmax(res,f[i][j]-(($L$)i*co1+co2));
    }

    fw(res+cnt,1);

    Heriko Deltana;
}

「5.0」缝合棋

五子棋和围棋缝在一起了(

「5.1」题目简述

Alice 和 Bob 两个人下棋,胜利规则就是有 \(m\) 个棋连成一条线(八个方向上的),输出胜利方的名字和决出胜负的步数。

定义违规为围棋中的“自杀”,即将自己的气堵死;或为下到了已经有棋的地方,输出 illegal

若所有操作都结束后未能分出胜负,那么输出 draw

「5.2」思路简述

显然是大模拟了,那么还是使用最强科技 DFS。

但是场上实际上想的是用冰茶姬去做,结果忘了二维转一维,于是二维冰茶姬写挂了(

「5.3」Code

CI MXX(1005);

#define illegal Heriko puts("illegal"),Deltana
#define draw puts("draw")
#define Alice(x) Heriko printf("Alice "),fw(x,1),Deltana
#define Bob(x) Heriko printf("Bob "),fw(x,1),Deltana

int n,m,mp[MXX][MXX];

bool vis[MXX][MXX];

vector< pair<int,int> > v[2],qwq;

bool DFS(int x,int y,int co)
{
    if(mp[x][y]<0) Heriko Romanno;

    if(mp[x][y]!=co or vis[x][y]) Heriko Deltana;

    vis[x][y]=1;qwq.push_back(mkp(x,y));

    Heriko (DFS(x-1,y,co) | DFS(x,y-1,co) | DFS(x+1,y,co) | DFS(x,y+1,co));
}

I bool CleanChecker(int x)
{
    bool flg(0);

    for(int i(0);i<(int)v[x].size();++i) vis[v[x][i].first][v[x][i].second]=0;

    for(int i(0);i<(int)v[x].size();++i)
    {
        int tx(v[x][i].first),ty(v[x][i].second);

        if(!vis[tx][ty] and (mp[tx][ty]==x))
        {
            qwq.clear();

            if(!DFS(tx,ty,x))
            {
                flg=1;

                for(int j(0);j<(int)qwq.size();++j) mp[qwq[j].first][qwq[j].second]=-1;
            }
        }
    }

    Heriko flg;
}

I bool Checkbox(int x,int y,int tx,int ty)
{
    int co(mp[x][y]),res(1);

    while(mp[x-tx][y-ty]==co) x-=tx,y-=ty;

    while(mp[x+tx][y+ty]==co) x+=tx,y+=ty,++res;
 
    Heriko res>=m;
}

I bool Checker(int x,int y) {Heriko (Checkbox(x,y,0,1) or Checkbox(x,y,1,1) or Checkbox(x,y,1,0) or Checkbox(x,y,1,-1));}

S main()
{
    Files();
    fr(n),fr(m);mst(mp,-1);
    
    for(int i(1);i<=n;++i)
    {
        int x,y,co;
        fr(x),fr(y);

        if(mp[x][y]>=0) illegal;

        co=mp[x][y]=(i&1);v[co].push_back(mkp(x,y));

        if(!CleanChecker(co^1) and CleanChecker(co)) illegal;

        if(Checker(x,y))
        {
            if(co) Alice(i);
            else Bob(i);
        }
    }

    draw;

    Heriko Deltana;
}   

「6.0」垃圾游戏

垃圾氪金游戏

「6.1」题意简述

\(L\) 这天又在打垃圾氪金游戏了。这次他终于遇到了最终 boss,最终 boss 会一个非常强大的技能,可以对一定的区域造成毁灭性的打击。这里我们把场地抽象成一个数轴,每一秒 boss 都会发动攻击,如果想要活命,小 \(L\) 必须到达指定的安全区域,安全区域是数轴上的若干闭区间。如果小 \(L\) 成功躲避了 \(n\) 次攻击,那么他的大招 CD 就好了,可以一招秒掉 boss。

由于一些原因,小 \(L\) 只能站在数轴的整点位置,他可以向左向右移动,移动不耗时间。向两边移动需要耗费一定的体力,每向左移动一格,会消耗 \(A\) 点体力值,每向右移动一格,会消耗 \(B\) 点体力值。现在,小 \(L\) 希望在消耗的总体力值最小的前提下,躲避 boss 的 \(n\) 轮攻击,你能帮他算算最少需要消耗的体力值吗?

注意,小 \(L\) 可以任意选择初始所在的位置。

\(1≤n≤2∗105,1≤q≤106,1≤A,B≤106,∑k_i≤106,1≤l_i≤r_i≤q.\)

「6.2」思路简述 and Code

考虑小 \(L\) 在第 \(i\) 秒的位置,它要么等于他在第 \(i+1\) 秒的位置,要么等于可行区间的端点。

最一开始写了个线段树,但是写挂了,于是就改成用 set

CI MXX(1e6+5);

const LL INF(1ll<<60);

int n,A,B,k,col[MXX],cor[MXX];

LL f[MXX];

set<int> T;

S main()
{
    Files();
    T.insert(0);
    fr(n),fr(A),fr(B);

    for(int i(1);i<=n;++i)
    {
        fr(k);

        if(i==1)
        {
            for(int j(1);j<=k;++j)
            {
                int l,r;fr(l),fr(r);

                for(int w(l);w<=r;++w) T.insert(w);
            }

            continue;
        }

        cor[0]=col[0]=0;
        
        for(int j(1);j<=k;++j)
        {
            int l,r;LL res(INF);fr(l),fr(r);
            col[j]=l,cor[j]=r;
            auto it(T.lower_bound(l));

            if(it!=T.end()) res=Hmin(res,f[*it]+1ll*A*(*it-l));

            if(it!=T.begin())
            {
                --it;

                if(it!=T.begin()) res=Hmin(res,f[*it]+1ll*B*(l-*it));
            }

            f[l]=res;res=INF;it=T.lower_bound(r);

            if(it!=T.end()) res=Hmin(res,f[*it]+1ll*A*(*it-r));

            if(it!=T.begin())
            {
                --it;

                if(it!=T.begin()) res=Hmin(res,f[*it]+1ll*B*(r-*it));
            }

            f[r]=res;
        }

        col[k+1]=cor[k+1]=MXX;

        for(int j(1);j<=k+1;++j)
        {
            auto it(T.lower_bound(col[j]));

            if(it==T.begin()) continue;

            --it;

            while(it!=T.begin() and cor[j-1]<(*it))
            {
                auto alpine(it);--alpine;
                T.erase(*it);it=alpine;
            }
        }

        for(int j(1);j<=k;++j) T.insert(col[j]),T.insert(cor[j]);
    }
    
    LL ans(INF);

    //for(auto it=T.begin();it!=T.end();++it) if(*it) ans=Hmin(ans,f[*it]);

    for(auto i:T) if(i) ans=Hmin(ans,f[i]);

    fw(ans,1);

    Heriko Deltana;
}

「7.0」尾声

由于大部分时间都滚回去 whk 了,这次补题时间也很长(

ZRNOIP21D1 是 \(60\) pts,然后 D2 变成 \(30\) pts,于是这次……

真的就是 \(0\) pts。

还是希望 CSP-S 2021 and NOIP 2021 RP++ 罢。

posted @ 2021-09-17 20:28  HerikoDeltana  阅读(128)  评论(0编辑  收藏  举报