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