SWERC 2019-2020 題解(全)

update PE707和這場的E很相似 Problem A: solver dc.fang 由於距離不超過100考慮將距離做爲dp的維度node

#include <iostream>
#include <cmath>
#include <cstdio>
#include <vector>
#include <string>
#include <set>
#include <set>
#include <cstring>
#include <algorithm>
#include <map>
#include <queue>
#include <stack>
#include <ctime>
#include <cmath>
#include <sstream>
#include <cstdlib>
#include <iomanip>
#include <list>
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
const int maxt = 11000;
const int maxn = 5e3 + 10;
const int inf = 0x3f3f3f3f;
const int maxe = 4e6 + 10;
struct Point {
	int x, y;
	vector<pii> e;
	int to(Point& b) {
		return ceil(sqrt(1.0*(x-b.x)*(x-b.x)+1.0*(y-b.y)*(y-b.y)));
	}
}o[maxn];
struct Edge {
	int v, w, c, nxt;
}edges[maxe];
int cnt = 0, head[maxn];
void add_edge(int u, int v, int w, int c) { // w 長度 c 費用
	edges[cnt] = {v, w, c, head[u]};
	head[u] = cnt++;
	edges[cnt] = {u, w, c, head[v]};
	head[v] = cnt++;
}
int B, C[maxt], T, N;
int ans = inf;
struct node {
	int i, c, w, pre;
};
int dp[1010][110];
void bfs(int s, int d)
{
	memset(dp, inf, sizeof(dp));
	queue<node> q;
	q.push(node{s, 0, 0, -1});
	while (!q.empty()) {
		auto it = q.front();
		int u = it.i, t = it.c, dis = it.w, fa = it.pre;
		q.pop();
		for (int i = head[u]; i != -1; i = edges[i].nxt) {
			int v = edges[i].v, w = edges[i].w, c = edges[i].c;
			if(fa == v) continue;
			if(dis + w <= B) {
//				cout << u << "->" << v << " : " << t + c << endl;
				if(v == d) {
					ans = min(ans, t + c);
					continue;
				}
				if(t+c < dp[v][dis+w]) {
					dp[v][dis+w] = t+c;
					q.push(node{v, t + c, dis + w, u});
				}
			}
		}
	}
}
int main() {
	ios::sync_with_stdio(false);
	Point s, d;
	cin >> s.x >> s.y >> d.x >> d.y;
	cin >> B >> C[0];
	cin >> T;
	for (int i = 1; i <= T; i++) cin >> C[i];
	cin >> N;
	
	memset(head, -1, sizeof(head));
	for (int i = 0; i < N; i++) {
		cin >> o[i].x >> o[i].y;
		int l; cin >> l;
		for (int j = 0; j < l; j++) {
			int t, m; cin >> t >> m;
			o[i].e.push_back(pii(t, m));
		}
	}
	
	for (int i = 0; i < N; i++) {
		for (auto& j : o[i].e) {
			int r = o[i].to(o[j.first]); // 長度
			j.second = C[j.second] * r; // 費用
			add_edge(i, j.first, r ,j.second);
		}
	}
	
	o[N] = s; o[N+1] = d;
	for (int i = 0; i < N; i++) {
		int r1 = o[i].to(o[N]);
		add_edge(N, i, r1, C[0] * r1);
		int r2 = o[i].to(o[N+1]);
		add_edge(N+1, i, r2, C[0] * r2);
	}
	add_edge(N, N+1, o[N].to(o[N+1]), o[N].to(o[N+1]) * C[0]);

	bfs(N, N+1);
	if(ans != inf) cout << ans << endl;
	else cout << -1 << endl;
}

Problem B: solver UCPRER 水題 Problem C: solver Hugin 水題 Problem D: 模擬題,主要考慮一下怎麼實現加括號和去括號。原始序列不須要很長由於每步操做最多隻能減小一個元素。ios

#include<stack>
#include<cstdio>
#include<cstring>
#include<map>
#include<iostream>
#include<cstdio>
#include<bits/stdc++.h>
using namespace std;
typedef pair<int,int>pii;
const int N=1e5+20;
pii unpair[N*2];
map<pii,int>ID;
stack<int> solve(string& s){
	stack<int>stk;
	static int id=N;
	for(int i=0;i<N;i++){
		stk.push(i);
	}
	function<bool(char)>work=[&](char op){
		if(op=='C'){
			stk.push(stk.top());	
			return 1;
		}		
		if(op=='D'){
			stk.pop();
			return 1;
		}
		if(op=='U'){
			int cur=stk.top();
			if(cur<N)
				return 0;
			stk.pop();
			pii& a=unpair[cur];
			stk.push(a.second);
			stk.push(a.first);			
			return 1;
		}
		if(op=='P'){
			int a=stk.top();
			stk.pop();
			int b=stk.top();
			stk.pop();
			if(ID.count({a,b})){
				stk.push(ID[{a,b}]);
			}
			else {
				stk.push(ID[{a,b}]=id);
				unpair[id++]={a,b};
			}
			return 1;
		}
		if(op=='S'){
			int a=stk.top();
			stk.pop();
			int b=stk.top();
			stk.pop();
			stk.push(a);
			stk.push(b);
			return 1;
		}
		if(op=='L'){
			if(work('U')&&work('S')&&work('D')){
				return 1;
			}
			return 0;
		}
		if(op=='R'){
			if(work('U')&&work('D')){
				return 1;	
			}
			return 0;
		}
	};
	for(char ch:s){
		if(!work(ch)){
			stack<int>t;
			return t;
		}
	}
	return stk;
}
int main(){
	string a,b;
	cin>>a>>b;
	stack<int>s=solve(a);
	stack<int>t=solve(b);
	if(s.size()!=t.size()){
		cout<<"False";
		return 0;
	}
	bool f=1;
	while(!s.empty()){
		if(s.top()!=t.top()){
			f=0;
			break;
		}
		s.pop();
		t.pop();
	}
	cout<<(f?"True":"False");
}

Problem E: solver Hugin 注意到肯定了一行或一列就能知道整個矩陣的值了,那麼將一行或一列做爲變量高斯消元。 複雜度O(min(C,R)^3/64+min(C,R)CR/64)c++

#include<bits/stdc++.h>
using namespace std;
const int N=300;
bitset<N>qu[N];
bool gauss(bitset<N>*a,int n){
    bitset<N>f;
    f[n]=1;
    for(int i=0;i<n;i++){
        int p=-1;
        for(int j=i;j<n;j++){
            if(a[j][i]){
                p=j;
                break;
            }
        }
        if(p!=-1){
            swap(a[i],a[p]);
            for(int j=0;j<n;j++){
                if(j==i)continue;
                if(a[j][i]){
                    a[j]^=a[i];
                }
            }
        }
    }
    for(int i=0;i<n;i++){
    	if(a[i]==f)
			return 0;
	}
    return 1;
}
int main()
{
    int n,m;
    scanf("%d%d",&n,&m);
    getchar();
    vector<vector<char>>a(n);
    for(int i=0;i<n;i++){
        a[i]=vector<char>(m);
        for(int j=0;j<m;j++){
            a[i][j]=getchar();
            getchar();
        }
    }
    bool f=0;
    if(n<m){
        f=1;
        vector<vector<char>>b(m);
        for(int i=0;i<m;i++){
            b[i]=vector<char>(n);
        }
        for(int i=0;i<n;i++){
            for(int j=0;j<m;j++){
                b[j][i]=a[i][j];
            }
        }
        swap(n,m);
        swap(a,b);
    }
    //n<m
    vector<vector<bitset<N>>>ma(n);
    for(int i=0;i<n;i++){
        ma[i]=vector<bitset<N>>(m);
    }
    for(int i=0;i<m;i++){
        ma[0][i][i]=1;//first row
    }
    for(int i=1;i<n;i++){
        //bitsize m
        for(int j=0;j<m;j++){
            bitset<N>&b=ma[i][j];
            b=ma[i-1][j];
			if(i-2>=0)
				b^=ma[i-2][j];
            if(j-1>=0){
                b^=ma[i-1][j-1];
            }
            if(j+1<m){
                b^=ma[i-1][j+1];
            }
            if(a[i-1][j]=='B'){
                b[m]=b[m]^1;
            }
        }
    }
    for(int i=0;i<m;i++){
        bitset<N>&b=qu[i];
        b=ma[n-1][i];
		if(n-2>=0)
			b^=ma[n-2][i];//n<2?
        if(i-1>=0){
            b^=ma[n-1][i-1];
        }
        if(i+1<m){
            b^=ma[n-1][i+1];
        }
        if(a[n-1][i]=='B'){
            b[m]=b[m]^1;
        }
    }
    if(gauss(qu,m)){
        bitset<N>sol;
        for(int i=0;i<m;i++){
            sol[i]=qu[i][m];
        }
        sol[m]=1;
        vector<vector<char>>ans(n);
        for(int i=0;i<n;i++){
            ans[i]=vector<char>(m);
        }
        for(int i=0;i<n;i++){
            for(int j=0;j<m;j++){
            	int t=(sol&ma[i][j]).count();
                if(t&1){
                    ans[i][j]='P';
                }
                else {
                    ans[i][j]='A';
                }
            }
        }
        if(!f){
            for(int i=0;i<n;i++){
                for(int j=0;j<m;j++){
                    putchar(ans[i][j]);
                    putchar(' ');
                }
                putchar('\n');
            }
        }
        else {
            for(int j=0;j<m;j++){
               for(int i=0;i<n;i++){
                    putchar(ans[i][j]);
                    putchar(' ');
                }
                putchar('\n');
            }
        }
    }
    else {
        printf("IMPOSSIBLE");
    }
}

Problem F: solver Hugin 多邊形面積套公式就行了 Problem G: solver Hugin 考慮反圖,不能交換的物種之間的順序已經固定了,那麼作一遍拓撲排序就好。ide

#include<bits/stdc++.h>
using namespace std;
const int N=1e5+100;
const int M=220;
vector<int>pos[M];
bitset<M>E[M];
bitset<M>F[M];
vector<int>ans;vector<string>name;
int ID(string x){
    return lower_bound(name.begin(),name.end(),x)-name.begin();
}
int main()
{
    int m,k,n;
    ios::sync_with_stdio(false);
    cin.tie(0);
    cin>>m>>k>>n;
    name.resize(m);
    for(int i=0;i<m;i++){
        cin>>name[i];
    }
    memset(E,-1,sizeof(E));
    for(int i=0;i<m;i++){
        E[i][i]=0;
    }
    sort(name.begin(),name.end());
    while(k--){
        int u,v;
        string a,b;
        cin>>a>>b;
        u=ID(a),v=ID(b);
        E[u][v]=E[v][u]=0;
    }
    for(int i=0;i<n;i++){
        string s;
        cin>>s;
        pos[ID(s)].push_back(i);
    }
    for(int i=0;i<m;i++){
        pos[i].push_back(n);
        reverse(pos[i].begin(),pos[i].end());
    }
    for(int i=0;i<m;i++){
        for(int j=0;j<m;j++){
            if(pos[i].back()>pos[j].back()){
                F[i][j]=1;
            }
        }
    }
    while(ans.size()<n){
        int id=0;
        while((id<m&&pos[id].back()==n)||(E[id]&F[id]).any()){
            id++;
        }
        ans.push_back(id);
        {
            pos[id].pop_back();
            for(int i=0;i<m;i++){
                F[i][id]=0;
                F[id][i]=0;
                if(pos[i].back()>pos[id].back()){
                    F[i][id]=1;
                }
                else if(pos[id].back()>pos[i].back()){
                    F[id][i]=1;
                }
            }
        }
    }
    for(int i=0;i<n;i++){
        cout<<name[ans[i]]<<' ';
    }
}

Problem H solver Hugin 找到循環節後分段打表。 Problem I 水題 Problem J: solver Hugin 最小值必定是子樹的根,相同的值能夠組成二叉樹。注意不直接相鄰的值也可能在樹上相鄰。spa

#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=3000000,P=1000000007;
int f[N+5],inv[N+5],inv2[N];
int qpow(int a,int b){
	int res=1;
	for(;b;b>>=1){
		if(b&1){
			res=1ll*res*a%P;
		}
		a=1ll*a*a%P;
	}
	return res;
}
int C(int n,int m){
	return 1ll*f[n]*inv[m]%P*inv[n-m]%P;
}
signed main()
{
	f[0]=1;
	for(int i=1;i<=N;i++){
		f[i]=1ll*f[i-1]*i%P;
	}
	inv[N]=qpow(f[N],P-2);
	for(int i=N-1;i>=1;i--){
		inv[i]=inv[i+1]*(i+1ll)%P;
		assert(1ll*f[i]*inv[i]%P==1);
	}
	inv2[1]=1;
	for(int i=2;i<=N;i++){
		inv2[i]=1ll*(P-P/i)*inv2[P%i]%P;
		assert(1ll*i*inv2[i]%P==1);
	}
	int n;
	cin>>n;
	int ans=1;
	inv[0]=1;
	stack<int>st;
	while(n--){
		int x,cur;
		cin>>x;
		cur=x;
		int c=1;
		while(!st.empty()&&x<st.top()){
			if(st.top()==cur)c++;
			else {
				ans=1ll*ans*C(2*c,c)%P*inv2[c+1]%P;
				cur=st.top(),c=1;
			}
			st.pop();
		}
		st.push(x);
		ans=1ll*ans*C(2*c,c)%P*inv2[c+1]%P;
	}
	int cur=-1,c=1;
	while(!st.empty()){
		if(cur==st.top())c++;
		else {
			ans=1ll*ans*C(2*c,c)%P*inv2[c+1]%P;
			cur=st.top(),c=1;
		}
		st.pop();
	}
	ans=1ll*ans*C(2*c,c)%P*inv2[c+1]%P;
	cout<<ans;
}

Problem K solver Hugin 就是考慮和T直接相鄰的點可否達到另外一個。用了一些比較垃圾的作法,tarjan縮點後dp可達點的數量,其實能夠一遍dfs搞定。code

#include<bits/stdc++.h>
using namespace std;
const int N=2e5;
vector<int>G[N];
vector<int>R[N];
int dfn[N],low[N],col[N];
stack<int>st;
bool instack[N];
int dfn_clock,ccnt; 
void tarjan(int u){
	dfn[u]=low[u]=++dfn_clock;
	st.push(u),instack[u]=true;
	for(int v:G[u]){
		if(!dfn[v]){
			tarjan(v);
			low[u]=min(low[u],low[v]);
		}
		else if(instack[v]){
			low[u]=min(low[u],dfn[v]);
		}
	}
	if(low[u]==dfn[u]){
		++ccnt;
		while(instack[u]){
			int v=st.top();
			col[v]=ccnt;
			instack[v]=false;
			st.pop();
		}
	}
}
vector<int>G2[N];
int w[N],dp[N];
bool vis[N];
void DP(int u){
	vis[u]=true;
	dp[u]=w[u];
	for(auto v:G2[u]){
		if(!vis[v])DP(v);
		dp[u]+=dp[v];
	}
}
int main()
{
	int n,m,T;
	cin>>n>>m>>T;
	vector<int>chk;
	while(m--){
		int u,v;
		cin>>u>>v;
		if(v==T)
			chk.push_back(u);
		else
			G[u].push_back(v);  
	}
	vector<int>ans;
	for(int i=0;i<n;i++){
		if(i==T)continue;
		if(!dfn[i])
			tarjan(i);
	}
	for(int i=0;i<n;i++){
		if(i==T)continue;
		for(int v:G[i]){
			if(col[i]==col[v]){
				continue;
			}
			G2[col[i]].push_back(col[v]);
		}
	}
	for(auto i:chk){
		w[col[i]]++;
	}
	for(int i=1;i<=ccnt;i++){
		if(!vis[i]){
			DP(i);
		}
	}
	for(auto i:chk){
		if(dp[col[i]]==1){
			ans.push_back(i);
		} 
	} 
	cout<<ans.size()<<endl;
	for(auto i:ans){
		cout<<i<<'\n';
	}
}

Problem L: solver Hugin 博弈題,考慮狀壓作。能夠發現溼地周圍的格子夠成的連通塊大小不超過20,並且兩片溼地的距離至少爲3保證了遊戲獨立。排序

#include<bits/stdc++.h>
#define int long long
using namespace std;
const int dx[]={1,-1,0,0},dy[]={0,0,1,-1};
typedef pair<int,int>pii;
int n;
char ma[10][10];
bool vis[10][10];
int id[10][10];
vector<pii> rev;
void get(pii cur,vector<pii>&v){
    for(int i=0;i<4;i++){
        pii to={cur.first+dx[i],cur.second+dy[i]};
        if(to.first<0||to.first>=n||to.second<0||to.second>=n||vis[to.first][to.second]){
            continue;
        }
        v.push_back(to);
    }
}
map<int,int>sg;
int divide(pii cur){
	queue<pii>q;
	q.push(cur);
	int ans=0;
	while(!q.empty()){
		vector<pii>to;
		pii cur=q.front();
		vis[cur.first][cur.second]=1;
		ans|=1ll<<id[cur.first][cur.second];
		get(cur,to);
		q.pop();
		for(pii v:to){
			if(id[v.first][v.second]!=-1){
				q.push(v); 
			}
		}
	}
	return ans;
}
int SG(int st){
	//cout<<st<<endl;
    if(st==0)
        return 0;
    if(sg.count(st)){
        return sg[st];
    }
    bool mex[64]{};
    int n=__lg(st);
    for(int i=0;i<=n;i++){
        if(st&(1ll<<i)){
            vector<pii>to;
            get(rev[i],to);
            int nst=st^(1ll<<i);
            for(pii x:to){
                int j=id[x.first][x.second];
                if(j==-1)continue;
                if(nst&(1ll<<j)){
                    nst^=1ll<<j;
                }
            }
            mex[min(SG(nst),n)]=1;
        }
    }
    for(int i=0;;i++){
        if(!mex[i]){
			return sg[st]=i;
		}
    }
}
int bfs(pii s){
    queue<pii>q;
    q.push(s);
    vector<pii>c;
    while(!q.empty()){
        pii cur=q.front();
        q.pop();
        vis[cur.first][cur.second]=true;
        vector<pii>to;
        get(cur,to);
        for(pii v:to){
            char ch=ma[v.first][v.second];
            if(ch=='*'){
                q.push(v);
            }
            else if(ch=='.'){
                vis[v.first][v.second]=1;
                c.push_back(v);
            }
        }
    }
    memset(id,-1, sizeof(id));
    rev.resize(c.size());
    for(int i=0;i<c.size();i++){
        pii cur=c[i];
        id[cur.first][cur.second]=i;
        vis[cur.first][cur.second]=0;
        rev[i]=cur;
    }
	vector<int>v;
	for(int i=0;i<c.size();i++){
		pii cur=c[i];
		if(!vis[cur.first][cur.second]){
			v.push_back(divide(cur));
		}	
	}
	for(int i=0;i<c.size();i++){
        pii cur=c[i];
        vis[cur.first][cur.second]=0;
    }
	if(v.size()>1){
		int ans=0;
		sg.clear();
		for(int i:v){
				ans^=SG(i);
		}
		return ans;
	}
    sg.clear();
    return SG((1ll<<c.size())-1);
}
signed main()
{
    int ans=0;
    scanf("%d",&n);
    for(int i=0;i<n;i++){
        scanf("%s",ma[i]);
    }
    for(int i=0;i<n;i++){
        for(int j=0;j<n;j++){
            if(vis[i][j])continue;
            if(ma[i][j]=='*'){
                int t=bfs({i,j});
                ans^=t;
            }
        }
    }
    printf("%s player will win\n",ans?"First":"Second");
}
相關文章
相關標籤/搜索