WY模拟赛4

WY模拟赛4

T1. 洛谷 P8763 [蓝桥杯 2021 国 ABC] 异或变换

原题

一道打表找规律题,但是被标签忽悠了。

通过偷税的打表操作,我们可以发现,对于一个长度为 $ n $ 的 $ 01 $ 串,存在一个最小的 $ 2^{x} $ 使得 $ n \leq 2^{x} $ ,此时 $ x $ 便是一个循环节,但不一定是最小循环节。

有了这个结论直接模拟即可。

code:

#include <bits/stdc++.h> 
#define i8  __int128
#define int long long 
#define fuck inline
#define lb long double 
using namespace std; 
// typedef long long ll; 
const int N=5e5+23,M=64,mod=536870912;
const int inf=INT_MAX,INF=1e9+7; 
// const int mod1=469762049,mod2=998244353,mod3=1004535809;
// const int G=3,Gi=332748118; 
// const int M=mod1*mod2;
fuck 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<<3)+(x<<1)+(c-'0');c=getchar();}
    return x*f;
}
fuck void write(int x)
{
    if(x<0){putchar('-');x=-x;}
    if(x>9) write(x/10);
    putchar(x%10+'0');
}
int a[N],n,k,b[N];
int cnt=1;
fuck void solve()
{
    cin>>n>>k;
    string s;cin>>s;
    for(int i=0;i<n;i++)a[i+1]=s[i]-'0';
    while(cnt<n)cnt<<=1;
    k=k%cnt;
    for(int o=1;o<=k;o++)
    {
        for(int i=1;i<=n;i++)
        {
            if(i==1)b[i]=a[i];
            else b[i]=a[i]^a[i-1];
        }
        for(int i=1;i<=n;i++)a[i]=b[i];
    }
    for(int i=1;i<=n;i++)cout<<a[i];
    cout<<endl;
}
signed main() 
{ 
    // ios::sync_with_stdio(false); 
    // cin.tie(0); cout.tie(0); 
    // int fuckccf=read();
    // int QwQ=read();
    // while(QwQ--)solve(); 
    solve(); 
    return 0; 
}
//  6666   66666  666666 
// 6    6  6   6      6 
// 6    6  6666      6 
// 6    6  6  6    6 
//  6666   6   6  6666666

T2. 洛谷 P10484 送礼物

原题

一道比较板子的折半搜索,但是写代码的时候脑子疑似被 $ IFMT $ 用导线短接了,把 $ cntb $ 敲成了 $ n $ 。

思路很显然,从数据入手,发现直接爆搜的话是 $ 2^{46} $ ,显然会 $ T $ 爆掉,但是如果是 $ 2^{23} $ 的话却能完美通过,于是就想到了折半搜索。将数据排序后,较为均等地分给两个集合,并爆搜枚举组合存下组合总值的信息,然后暴力地跑任意一个集合里的元素 $ x $ ,并在另一个集合中寻找最大的 $ y $ 使得, $ x+y \leq w $ ,显然这得用二分,然后更新最大值即可。

#include <bits/stdc++.h> 
#define i8  __int128
#define int long long 
#define fuck inline
#define lb long double 
using namespace std; 
// typedef long long ll; 
const int N=8388608+5,M=64,mod=536870912;
const int inf=INT_MAX,INF=1e9+7; 
// const int mod1=469762049,mod2=998244353,mod3=1004535809;
// const int G=3,Gi=332748118; 
// const int M=mod1*mod2;
fuck 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<<3)+(x<<1)+(c-'0');c=getchar();}
    return x*f;
}
fuck void write(int x)
{
    if(x<0){putchar('-');x=-x;}
    if(x>9) write(x/10);
    putchar(x%10+'0');
}
int p[N],n,w,len;
int a[N],b[N],cnta=0,cntb=0;
fuck void dfs(int pos,int sum)
{
    if(pos>len){a[++cnta]=sum;return;}
    dfs(pos+1,sum);
    dfs(pos+1,sum+p[pos]);
}
fuck void dfs2(int pos,int sum)
{
    if(pos>n){b[++cntb]=sum;return;}
    dfs2(pos+1,sum);
    dfs2(pos+1,sum+p[pos]);
}
int ans=0;
fuck void solve()
{
    cin>>w>>n;
    for(int i=1;i<=n;i++)cin>>p[i];
    sort(p+1,p+n+1);
    // for(int i=1;i<=n;i++)cout<<p[i]<<" ";
    // cout<<endl;
    len=(n>>1);
    // cout<<len<<endl;
    dfs(1,0);
    dfs2(len+1,0);
    sort(a+1,a+cnta+1);
    sort(b+1,b+cntb+1);
    // for(int i=1;i<=cnta;i++)cout<<a[i]<<" ";
    // cout<<endl;
    // for(int i=1;i<=cntb;i++)cout<<b[i]<<" ";
    // cout<<endl;
    for(int i=1;i<=cnta;i++)
    {
        if(a[i]>w)continue;
        int res=w-a[i];
        int pos=upper_bound(b+1,b+cntb+1,res)-b;
        // cout<<pos<<endl;
        ans=max(ans,a[i]+b[pos-1]);
    }
    cout<<ans<<endl;
}
signed main() 
{ 
    // ios::sync_with_stdio(false); 
    // cin.tie(0); cout.tie(0); 
    // int fuckccf=read();
    // int QwQ=read();
    // while(QwQ--)solve(); 
    solve(); 
    return 0; 
}
//  6666   66666  666666 
// 6    6  6   6      6 
// 6    6  6666      6 
// 6    6  6  6    6 
//  6666   6   6  6666666

T3. 洛谷 P2346 四子连棋

原题

同样一道是搜索题,但是我们并不能确定 $ dfs $ 的层数,所以需要对层数进行限制,于是就使用迭代加深搜索解决这个问题。只需要每次对深度进行一个限制,跑到一定的深度后返回,防止一头扎得过深,然后每次改变当前状态时, $ check $ 一下改变后的状态是否已经合法即可。

注意:开局状态可能已经合法,需要特判。

#include <bits/stdc++.h> 
#define i8  __int128
#define int long long 
#define fuck inline
#define lb long double 
using namespace std; 
// typedef long long ll; 
const int N=5e5+23,M=64,mod=536870912;
const int inf=INT_MAX,INF=1e9+7; 
// const int mod1=469762049,mod2=998244353,mod3=1004535809;
// const int G=3,Gi=332748118; 
// const int M=mod1*mod2;
fuck 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<<3)+(x<<1)+(c-'0');c=getchar();}
    return x*f;
}
fuck void write(int x)
{
    if(x<0){putchar('-');x=-x;}
    if(x>9) write(x/10);
    putchar(x%10+'0');
}
int a[10][10];
int deep,ans=inf;
fuck bool check(int x,int y)
{
    if((a[1][y]==a[2][y]&&a[2][y]==a[3][y]&&a[3][y]==a[4][y])||(a[x][1]==a[x][2]&&a[x][2]==a[x][3]&&a[x][3]==a[x][4]))return true;
    if(x==y&&a[1][1]==a[2][2]&&a[2][2]==a[3][3]&&a[3][3]==a[4][4])return true;
    if(x+y==5&&a[1][4]==a[2][3]&&a[2][3]==a[3][2]&&a[3][2]==a[4][1])return true;
    return false;
}
fuck void dfs(int d,int op)
{
    if(d>deep){return;}
    for(int i=1;i<=4;i++)
        for(int j=1;j<=4;j++)
        {
            if(op==a[i][j])
            {
                if(a[i][j+1]==0)
                {
                    a[i][j+1]+=op;
                    a[i][j]-=op;
                    if(check(i,j+1))
                    {
                        // cout<<"aaaaaaaaaaaaaaa"<<endl;
                        // cout<<op<<" "<<i<<" "<<j<<endl;
                        ans=min(ans,d);
                    }
                    dfs(d+1,op==1?2:1);
                    a[i][j+1]-=op;
                    a[i][j]+=op;
                }
                if(a[i][j-1]==0)
                {
                    a[i][j-1]+=op;
                    a[i][j]-=op;
                    if(check(i,j-1))
                    {
                        // cout<<"bbbbbbbbbbbbbb"<<endl;
                        // cout<<op<<" "<<i<<" "<<j<<endl;
                        ans=min(ans,d);
                    }
                    dfs(d+1,op==1?2:1);
                    a[i][j-1]-=op;
                    a[i][j]+=op;
                }
                if(a[i+1][j]==0)
                {
                    a[i+1][j]+=op;
                    a[i][j]-=op;
                    if(check(i+1,j))
                    {
                        // cout<<"cccccccccccccc"<<endl;
                        // cout<<op<<" "<<i<<" "<<j<<endl;
                        ans=min(ans,d);
                    }
                    dfs(d+1,op==1?2:1);
                    a[i+1][j]-=op;
                    a[i][j]+=op;
                }
                if(a[i-1][j]==0)
                {
                    a[i-1][j]+=op;
                    a[i][j]-=op;
                    if(check(i-1,j))
                    {
                        // cout<<op<<" "<<i<<" "<<j<<endl;
                        ans=min(ans,d);
                    }
                    dfs(d+1,op==1?2:1);
                    a[i-1][j]-=op;
                    a[i][j]+=op;
                }
            }
        }
    
}
fuck void solve()
{
    memset(a,0x3f,sizeof(a));
    for(int i=1;i<=4;i++)
    {
        string s;cin>>s;
        for(int j=0;j<s.size();j++)
        {
            if(s[j]=='B')a[i][j+1]=1;
            else if(s[j]=='W')a[i][j+1]=2;
            else a[i][j+1]=0;
        }
    }
    // for(int i=1;i<=4;i++)
    // {
    //     for(int j=1;j<=4;j++)cout<<a[i][j]<<" ";
    //     cout<<endl;
    // }
    for(int i=1;i<=4;i++)
        for(int j=1;j<=4;j++)
        {
            if(check(i,j)){cout<<0<<endl;return;}
        }
    for(int i=1;i<=1000;i++)
    {
        deep=i;
        dfs(1,1);dfs(1,2);
        if(ans!=inf){cout<<ans<<endl;return;}
    }
}
signed main() 
{ 
    // ios::sync_with_stdio(false); 
    // cin.tie(0); cout.tie(0); 
    // int fuckccf=read();
    // int QwQ=read();
    // while(QwQ--)solve(); 
    solve(); 
    return 0; 
}
//  6666   66666  666666 
// 6    6  6   6      6 
// 6    6  6666      6 
// 6    6  6  6    6 
//  6666   6   6  6666666

T4. 洛谷 P5507 机关

原题

补的时候才发现居然之前没过。

需要设计一个估值函数来进行剪枝,加快搜索效率。具体的估值函数 $ h(x) $ :每个按钮分别旋转到 $ 1 $ 的值。在此优化上去搜索即可。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=(1<<24)+10;
int g[N],nxt[15][10];
int vis[N],lt[N],bt[N];
struct node
{
    int sta;
    double f;
    node(int s)
    {
        double h=0;
        f=0;sta=s;
        for(int i=0;i<12;i++)h+=(4-((s>>(i*2))&3))&3;
        h/=2;
        f=h+g[s];
    }
    friend bool operator <(node y, node x) {return x.f < y.f;}
};
int frz;
void as()
{
    priority_queue<node>q;
    q.push(node(frz));vis[frz]=1;
    while(!q.empty())
    {
        int st=q.top().sta;q.pop();
        if(st==0)break;
        for(int i=0;i<12;i++)
        {
            int sti=(st>>(i*2))%4, di=nxt[i][sti],stdi=(st>>(di*2))%4;
			int dst=st^(sti<<(i*2))^(((sti+1)%4)<<(i*2));
            dst=dst^(stdi<<(di*2))^(((stdi+1)%4)<<(di*2));
            if(!vis[dst])
            {
                g[dst]=g[st]+1,vis[dst]=1;
                lt[dst]=st,bt[dst]=i+1;
                q.push(node(dst));
            }
        }
    }
}
void _cout(int x)
{
    if(x==frz)return;
    _cout(lt[x]),cout<<bt[x]<<" ";
}
int main()
{
    // freopen("1.in","r",stdin); 
    // freopen("1.out","w",stdout); 
   int b;
   for(int i=0;i<12;i++)
    {
        cin>>b;
        frz|=((b-1)<<(i*2));
        for(int j=0;j<4;j++) cin>>nxt[i][j],nxt[i][j]--;
    }
    as();
    cout<<g[0]<<"\n";
    _cout(0);
    return 0;
}

总结

进步:

  1. 代码能力有所提升,可以独立自主实现想法;
  2. 思考速度有所提升,方向把握正确;

不足:

  1. 常用的技巧掌握不够充分, $ T1 $ 没有进行大量的打表;
  2. 思考不够全面,存在遗漏问题的特殊情况的缺陷;
  3. 写代码时存在低级错误, $ T2 $ 中将 $ cntb $ 敲成 $ n $ 。

完结收工!!!!!

个人主页

看完点赞,养成习惯

\(\Downarrow\Downarrow\Downarrow\Downarrow\Downarrow\Downarrow\Downarrow\Downarrow\Downarrow\Downarrow\Downarrow\Downarrow\Downarrow\Downarrow\Downarrow\Downarrow\Downarrow\Downarrow\Downarrow\Downarrow\Downarrow\Downarrow\Downarrow\Downarrow\Downarrow\)

posted @ 2025-07-07 19:27  Nightmares_oi  阅读(15)  评论(0)    收藏  举报