河南萌新联赛2024第(二)场 (CDEG)
C、小w和大W的决斗
博弈论
sg函数打表即可
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define int ll
#define endl '\n'
#define fi first
#define se second
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define per(i,a,b) for(int i=a;i>=b;i--)
#define lyh(i,a,b) for(int i=a;i<b;i++)
#define hyl(i,a,b) for(int i=a;i>b;i--)
typedef pair<int,int> PII;
typedef unsigned long long ull;
const int ddx[8]={-1, 0, 1, 0, 1, -1, 1, -1};
const int ddy[8]={0, 1, 0, -1, -1, 1, 1, -1};
const int INF=0x3f3f3f3f;
const int N=2e5+10;
const int M=1010;
int n,m;
int mod,fa[N];
int Fpow(int b,int p){long long res=1;for(;p;p>>=1,b=b*b%mod)if(p&1)res=res*b%mod;return res;}
int qmi(ll a,ll k,ll p){ll res = 1;while (k) {if (k&1) res = res * a % p; k >>= 1;a = a * a % p;}return res;}
void init() {for(int i=1;i<=n;i++) fa[i]=i;}
int find(int x) {return fa[x]==x?x:fa[x]=find(fa[x]);}
void add(int a,int b) {int x=find(a);int y=find(b);fa[x]=y;}
bool ask(int a,int b) {return find(a)==find(b);}
int a[N];
vector<int>f(105,-1);
int sg(int x)
{
if(f[x]!=-1) {
return f[x];
}
set<int>st;
for(int i=1;i<=x;i++) //操作一
{
st.insert(sg(x-i));
}
for(int i = 1;i<x-2;i++) //操作二
{
for(int j = 1;i+j<x;j++)
{
st.insert(sg(i)^sg(j)^sg(x-i-j));
}
}
for(int i=0;;i++)
{
if(!st.count(i)) return f[x] = i;
}
}
void solve()
{
cin>>n;
int ans = 0;
for (int i = 1;i <= n;i ++)
{
int x;
cin >> x;
ans ^= sg(x);
}
if(ans>0){
cout<<"w win"<<endl;
return;
}else{
cout<<"W win"<<endl;
return;
}
}
signed main() {
ios::sync_with_stdio(0);
cin.tie(0);
int t=1;
//cin >> t;
while(t--) {
solve();
}
return 0;
}
D、A*BBBB
题解中说:模拟乘法发现,当B每一位相同时假设为x,那么就是A乘x,然后B有多少位就往前移多少次,然后再用前缀和进行维护当前位数为多少。
我们首先举一个例子:114514 与 22222 相乘
114514*2 = 229028
114514 与 22222 相乘
1 1 4 5 1 4
x 2 2 2 2 2
--------------------
2 2 9 0 2 8
2 2 9 0 2 8
2 2 9 0 2 8
2 2 9 0 2 8
2 2 9 0 2 8
---------------------
我们都知道,答案的总长度是|a|+|b|
相乘结果的每一列都是一个区间
用l和r表达这个区间,并用前缀和和差分计算即可
8
2 8
0 2 8
9 0 2 8
2 9 0 2 8
2 2 9 0 2
2 2 9 0
2 2 9
2 2
2
code:
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define int ll
#define endl '\n'
#define fi first
#define se second
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define per(i,a,b) for(int i=a;i>=b;i--)
#define lyh(i,a,b) for(int i=a;i<b;i++)
#define hyl(i,a,b) for(int i=a;i>b;i--)
typedef pair<int,int> PII;
typedef unsigned long long ull;
const int ddx[8]={-1, 0, 1, 0, 1, -1, 1, -1};
const int ddy[8]={0, 1, 0, -1, -1, 1, 1, -1};
const int INF=0x3f3f3f3f;
const int N=5e6+10;
const int M=1010;
int n,m;
int mod,fa[N];
int Fpow(int b,int p){long long res=1;for(;p;p>>=1,b=b*b%mod)if(p&1)res=res*b%mod;return res;}
int qmi(ll a,ll k,ll p){ll res = 1;while (k) {if (k&1) res = res * a % p; k >>= 1;a = a * a % p;}return res;}
void init() {for(int i=1;i<=n;i++) fa[i]=i;}
int find(int x) {return fa[x]==x?x:fa[x]=find(fa[x]);}
void add(int a,int b) {int x=find(a);int y=find(b);fa[x]=y;}
bool ask(int a,int b) {return find(a)==find(b);}
string a,b;
int pr[N];
void solve()
{
cin>>a>>b;
if(a[0]=='0'||b[0]=='0'){
cout<<0<<endl;
return;
}
reverse(a.begin(),a.end()); //乘法是从个位开始向前计算的
vector<int>v;
int B = b[0]-'0';
int t = 0;
for (int i = 0; i < a.size(); i ++ ) //计算A与B【0】的乘积
{
t += (a[i]-'0')*B;
v.push_back(t % 10);
t /= 10;
}
while(t)
{
v.push_back(t % 10);
t /= 10;
}
reverse(v.begin(),v.end());
//求前缀和
//这里从1开始记录,方便计算
for(int i=1;i<=v.size();i++)
{
pr[i] = pr[i-1]+v[i-1];
}
int n = v.size();
int m = b.size();
int p = 0;
vector<int>ans;
for(int i =1;i<=n+m-1;i++) //模拟A与BBB……相乘的加法
{
int l =max(0ll,n-i);
int r = min(n,n+m-i);
p += pr[r]-pr[l];
ans.push_back(p%10);
p/=10;
}
while(p){
ans.push_back(p%10);
p/=10;
}
reverse(ans.begin(),ans.end());
for(int i=0;i<ans.size();i++) cout<<ans[i];
cout<<endl;
}
signed main() {
ios::sync_with_stdio(0);
cin.tie(0);
int t=1;
cin >> t;
while(t--) {
solve();
}
return 0;
}
E、“好”字符
这题考察了字符串哈希
字符串哈希模板:
核心思想:将字符串看成P进制数,P的经验值是131或13331,取这两个值的冲突概率低
小技巧:取模的数用2^64,这样直接用unsigned long long存储,溢出的结果就是取模的结果
typedef unsigned long long ULL;
ULL h[N], p[N]; // h[k]存储字符串前k个字母的哈希值, p[k]存储 P^k mod 2^64
// 初始化
p[0] = 1;
for (int i = 1; i <= n; i ++ )
{
h[i] = h[i - 1] * P + str[i];
p[i] = p[i - 1] * P;
}
// 计算子串 str[l ~ r] 的哈希值
ULL get(int l, int r)
{
return h[r] - h[l - 1] * p[r - l + 1];
}
操作1 :将字符串复制并连接在结尾。
操作2 :将字符串根据每个字符是否为字符 转化为一个01串(或将字符x以外的字符全部转化为特殊字符)
code
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define int ll
#define endl '\n'
#define fi first
#define se second
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define per(i,a,b) for(int i=a;i>=b;i--)
#define lyh(i,a,b) for(int i=a;i<b;i++)
#define hyl(i,a,b) for(int i=a;i>b;i--)
typedef pair<int,int> PII;
typedef unsigned long long ull;
const int ddx[8]={-1, 0, 1, 0, 1, -1, 1, -1};
const int ddy[8]={0, 1, 0, -1, -1, 1, 1, -1};
const int INF=0x3f3f3f3f;
const int N=1e6+10;
const int M=1010;
int n,m;
int mod,fa[N];
int Fpow(int b,int p){long long res=1;for(;p;p>>=1,b=b*b%mod)if(p&1)res=res*b%mod;return res;}
int qmi(ll a,ll k,ll p){ll res = 1;while (k) {if (k&1) res = res * a % p; k >>= 1;a = a * a % p;}return res;}
void init() {for(int i=1;i<=n;i++) fa[i]=i;}
int find(int x) {return fa[x]==x?x:fa[x]=find(fa[x]);}
void add(int a,int b) {int x=find(a);int y=find(b);fa[x]=y;}
bool ask(int a,int b) {return find(a)==find(b);}
const ull P =131;
ull h1[N],h2[2*N],p[2*N];
void getb(string s,char c,ull* h) //初始化
{
for (int i = 1; i <s.size(); i ++ )
{
h[i] = h[i - 1] * P + (s[i] == c);
}
}
int get(ull *h,int l, int r) //计算哈希值
{
return h[r] - h[l - 1] * p[r - l + 1];
}
string a,b;
void solve()
{
p[0]=1;
cin>>n;
cin>>a>>b;
set<char>st(a.begin(),a.end());
a=" "+a;
b=" "+b+b;
for(int i=1;i<N*2;i++)
{
p[i]=p[i-1]*P;
}
int ans = 0;
for(char c:st){
getb(a,c,h1);
getb(b,c,h2);
for(int i=1;i<=n;i++)
{
if(get(h2,i,i+n-1)==get(h1,1,n))
{
ans++;
break;
}
}
}
cout<<ans<<endl;
return;
}
signed main() {
ios::sync_with_stdio(0);
cin.tie(0);
int t=1;
//cin >> t;
while(t--) {
solve();
}
return 0;
}
G、lxy的通风报信
bfs+prim最短路
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define int ll
#define endl '\n'
#define fi first
#define se second
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define per(i,a,b) for(int i=a;i>=b;i--)
#define lyh(i,a,b) for(int i=a;i<b;i++)
#define hyl(i,a,b) for(int i=a;i>b;i--)
typedef pair<int,int> PII;
typedef unsigned long long ull;
const int ddx[8]={-1, 0, 1, 0, 1, -1, 1, -1};
const int ddy[8]={0, 1, 0, -1, -1, 1, 1, -1};
const int INF=0x3f3f3f3f;
const int N=2e5+10;
const int M=1010;
int n,m;
int mod,fa[N];
int Fpow(int b,int p){long long res=1;for(;p;p>>=1,b=b*b%mod)if(p&1)res=res*b%mod;return res;}
int qmi(ll a,ll k,ll p){ll res = 1;while (k) {if (k&1) res = res * a % p; k >>= 1;a = a * a % p;}return res;}
void init() {for(int i=1;i<=n;i++) fa[i]=i;}
int find(int x) {return fa[x]==x?x:fa[x]=find(fa[x]);}
void add(int a,int b) {int x=find(a);int y=find(b);fa[x]=y;}
bool ask(int a,int b) {return find(a)==find(b);}
char f[M][M];
int a[M][M];
int g[M][M];
int cnt = 0;
int ts = 1;
void bfs(int sx,int sy)
{
queue<PII>q;
q.push({sx,sy});
vector<vector<int>>dist(1010,vector<int>(1010,0));
vector<vector<int>>st(1010,vector<int>(1010,0));
dist[sx][sy]=0;
st[sx][sy]=1;
ts = 1;
while(!q.empty())
{
auto t = q.front();
q.pop();
int x = t.fi;
int y = t.se;
if(a[x][y]){
g[a[sx][sy]][a[x][y]]=dist[x][y];
}
for(int i=0;i<4;i++)
{
for(int j=0;j<4;j++)
{
int nx = x+ddx[i];
int ny = y+ddy[i];
if(st[nx][ny]||nx<1||nx>n||ny<1||ny>m||f[nx][ny]=='#') continue;
q.push({nx,ny});
st[nx][ny]=1;
if(f[nx][ny]=='*')
{
ts++;
}
dist[nx][ny] = dist[x][y]+1;
}
}
}
}
int prim()
{
vector<int>dis(1010,INF);
vector<int>vis(1010);
dis[1] = 0;
int res = 0;
for (int i =1;i<=cnt; i ++ )
{
int t = -1;
for (int j = 1; j <= cnt; j ++ )
if (!vis[j] && (t == -1 || dis[t] > dis[j]))
t = j;
res += dis[t];
vis[t] = true;
for (int j = 1; j <= n; j ++ ) dis[j] = min(dis[j], g[t][j]);
}
return res;
}
void solve()
{
cin>>n>>m;
rep(i,1,n)
{
rep(j,1,m)
{
cin>>f[i][j];
if(f[i][j] == '*')
{
a[i][j] = ++cnt;
}
}
}
rep(i,1,n)
{
rep(j,1,m)
{
if(a[i][j]){
bfs(i,j);
if(ts<cnt){
cout<<"No"<<endl;
return;
}
}
}
}
cout<<prim()<<endl;
}
signed main() {
ios::sync_with_stdio(0);
cin.tie(0);
int t=1;
//cin >> t;
while(t--) {
solve();
}
return 0;
}