河南萌新聯賽2024第(二)場 (CDEG)

羽原花發表於2024-07-26

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;
}

相關文章