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;
}
总结
进步:
- 代码能力有所提升,可以独立自主实现想法;
- 思考速度有所提升,方向把握正确;
不足:
- 常用的技巧掌握不够充分, $ T1 $ 没有进行大量的打表;
- 思考不够全面,存在遗漏问题的特殊情况的缺陷;
- 写代码时存在低级错误, $ 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\)

浙公网安备 33010602011771号