• SWERC 2019-2020 题解(全)


    update PE707和这场的E很类似
    Problem A:
    solver dc.fang
    因为距离不超过100考虑将距离作为dp的维度

    #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:
    模拟题,主要考虑一下怎么实现加括号和去括号。原始序列不需要很长因为每步操作最多只能减少一个元素。

    #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)

    #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('
    ');
                }
            }
            else {
                for(int j=0;j<m;j++){
                   for(int i=0;i<n;i++){
                        putchar(ans[i][j]);
                        putchar(' ');
                    }
                    putchar('
    ');
                }
            }
        }
        else {
            printf("IMPOSSIBLE");
        }
    }
    

    Problem F:
    solver Hugin
    多边形面积套公式就好了
    Problem G:
    solver Hugin
    考虑反图,不能交换的物种之间的顺序已经固定了,那么做一遍拓扑排序就好。

    #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
    最小值一定是子树的根,相同的值可以组成二叉树。注意不直接相邻的值也可能在树上相邻。

    #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搞定。

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

    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
    ",ans?"First":"Second");
    }
    
  • 相关阅读:
    《需求工程-软件建模与分析之读书笔记之五》
    Neo4j (3.3.9)的学习之路(1)
    大数据培训第一天总结
    京东B2B业务架构演变阅读心得
    小米网抢购系统开发实践阅读心得
    余额宝技术架构及演进阅读心得
    美图数据统计分析平台架构演进阅读心得
    荔枝架构实践与演进历程阅读心得
    去哪儿网支付系统架构演进全历程阅读心得
    基于SOA质量属性的系统构架分析与实践
  • 原文地址:https://www.cnblogs.com/hugin/p/12433064.html
Copyright © 2020-2023  润新知