ACM-ICPC 2018 Xuzhou Online Contest题解
首先,送上dalao的题解吧。 传送门
A. Hard to prepare 题目链接
题意:一个环形的 n 的列表每个数都是 0 到 2k−1,求相邻两个数同或不为 0 的方案数。
题解:来自dalao 链接
mask[i] XNOR mask[1] >> 0 即:2进制下至少一位相同
定义:
- dp[i][0] —— 至第ii个人分发面具的方案数,且 mask[i] = mask[1]
- dp[i][1] —— 至第ii个人分发面具的方案数,且 mask[i] XNOR mask[1] = 0
- dp[i][2] —— 至第ii个人分发面具的方案数,且 mask[i] ≠≠ mask[1],mask[i] XNOR mask[1] ≠≠ 0
可以推得转移方程:
- dp[i][0]=dp[i−1][0]+dp[i−1][2]dp[i][0]=dp[i−1][0]+dp[i−1][2]
- dp[i][1]=dp[i−1][1]+dp[i−1][2]dp[i][1]=dp[i−1][1]+dp[i−1][2]
- dp[i][0]=(dp[i−1][0]+dp[i−1][1])∗(2k−2)+dp[i−1][2]∗(2k−3)
1 #include<bits/stdc++.h> 2 using namespace std; 3 4 const int maxn = 1e6+100; 5 const int mod = 1e9+7; 6 int T,n,k; 7 long long dp[maxn][3],p[maxn]; 8 9 void pre() 10 { 11 p[0] = 1; 12 for (int i=1;i<=maxn-100;i++) 13 { 14 p[i] = p[i-1]+p[i-1]; 15 if (p[i] >= mod) p[i]-=mod; 16 } 17 return; 18 } 19 20 int main() 21 { 22 pre(); 23 scanf("%d",&T); 24 while (T--) 25 { 26 scanf("%d %d",&n,&k); 27 dp[1][0] = 1; 28 for (int i=2;i<=n;i++) 29 { 30 dp[i][0] = (dp[i-1][0] + dp[i-1][2]) % mod; 31 dp[i][1] = (dp[i-1][1] + dp[i-1][2]) % mod; 32 dp[i][2] = (((dp[i-1][0] + dp[i-1][1])*(p[k]-2+mod)) % mod + (dp[i-1][2]*(p[k]-3+mod)) % mod) % mod; 33 } 34 long long ans = ((dp[n][0] + dp[n][2])*p[k]) % mod; 35 printf("%lld\n",ans); 36 } 37 return 0; 38 }
B. BE, GE or NE 题目传送门
记忆化搜索+博弈SG
1 #include<bits/stdc++.h> 2 using namespace std; 3 4 const int maxn = 1010; 5 const int INF = 1e8; 6 int n,m,l,r,a[maxn],b[maxn],c[maxn]; 7 int dp[maxn][210]; 8 9 int dfs(int i,int sc) 10 { 11 if (i == n+1) return sc; 12 if (dp[i][sc+100] != INF) return dp[i][sc+100]; 13 14 int cnt,tmp; 15 if (i % 2)/**first**/ 16 { 17 tmp = -100; 18 if (a[i]) 19 { 20 cnt = min(100,sc+a[i]); 21 tmp = max(tmp,dfs(i+1,cnt)); 22 } 23 if (b[i]) 24 { 25 cnt = max(-100,sc-b[i]); 26 tmp = max(tmp,dfs(i+1,cnt)); 27 } 28 if (c[i]) 29 { 30 cnt = sc*(-1); 31 tmp = max(tmp,dfs(i+1,cnt)); 32 } 33 tmp = min(100,max(-100,tmp)); 34 dp[i][sc+100] = tmp; 35 } 36 else 37 { 38 tmp = 100; 39 if (a[i]) 40 { 41 cnt = min(100,sc+a[i]); 42 tmp = min(tmp,dfs(i+1,cnt)); 43 } 44 if (b[i]) 45 { 46 cnt = max(-100,sc-b[i]); 47 tmp = min(tmp,dfs(i+1,cnt)); 48 } 49 if (c[i]) 50 { 51 cnt = sc*(-1); 52 tmp = min(tmp,dfs(i+1,cnt)); 53 } 54 dp[i][sc+100] = tmp; 55 } 56 return dp[i][sc+100]; 57 } 58 59 int main() 60 { 61 scanf("%d %d %d %d",&n,&m,&r,&l); 62 for (int i=1;i<=n;i++) 63 scanf("%d %d %d",&a[i],&b[i],&c[i]); 64 for (int i=0;i<=n;i++) 65 for (int j=0;j<=200;j++) dp[i][j] = INF; 66 67 int ans = dfs(1,m); 68 if (ans >= r) printf("Good Ending\n"); 69 else 70 if (ans <= l) printf("Bad Ending\n"); 71 else 72 printf("Normal Ending\n"); 73 return 0; 74 }
C. Cacti Lottery 题目传送门
我补题的时候还是不会,附上别人的暴力解法代码吧
1 #include <bits/stdc++.h> 2 using namespace std; 3 typedef long long ll; 4 int num[25] = { 0,0,0,0,0,0,10000,36,720,360,80,252,108,72,54,180,72,180,119,36,360,1080,144,1800,3600}; 5 char mp[5][5]; 6 int vis[10]; 7 int cnt = 0, cnt1 = 0, cnt2 = 0; 8 char mp2[10]; 9 int fial[10]; 10 int idx = 0; 11 double allans = 0; 12 int ans[10]; 13 int A(int n, int m) 14 { 15 int res = 1; 16 for (int i = 1; i <= m; i++) { 17 res *= (n - i + 1); 18 } 19 return res; 20 } 21 void check1() 22 { 23 ans[0] += num[fial[0] + fial[1] + fial[2]]; 24 ans[1] += num[fial[3] + fial[4] + fial[5]]; 25 ans[2] += num[fial[6] + fial[7] + fial[8]]; 26 ans[3] += num[fial[0] + fial[3] + fial[6]]; 27 ans[4] += num[fial[1] + fial[4] + fial[7]]; 28 ans[5] += num[fial[2] + fial[5] + fial[8]]; 29 ans[6] += num[fial[0] + fial[4] + fial[8]]; 30 ans[7] += num[fial[2] + fial[4] + fial[6]]; 31 32 } 33 34 void dfs2(int num) 35 { 36 if (num == 9) 37 { 38 check1(); 39 return; 40 } 41 if (fial[num] != 0) dfs2(num + 1); 42 else { 43 for (int i = 1; i <= 9; i++) 44 { 45 if (vis[i])continue; 46 vis[i] = 1; 47 fial[num] = i; 48 dfs2(num + 1); 49 fial[num] = 0; 50 vis[i] = 0; 51 } 52 } 53 } 54 55 void dfs(int num) 56 { 57 if (num == 9) 58 { 59 memset(ans, 0, sizeof(ans)); 60 dfs2(0); 61 int maxx = 0; 62 for (int i = 0; i < 8; i++) 63 { 64 maxx = max(maxx, ans[i]); 65 66 } 67 /*if (maxx) 68 cout << maxx << endl;*/ 69 allans += maxx / (A(cnt2,cnt2)*1.0); 70 return; 71 } 72 if (mp2[num] == '#') { dfs(num + 1); } 73 else if (mp2[num] != '*') { fial[num] = mp2[num] - '0'; dfs(num + 1); } 74 else { 75 for (int i = 1; i <= 9; i++) 76 { 77 if (vis[i]) continue; 78 vis[i] = 1; 79 fial[num] = i; 80 dfs(num + 1); 81 vis[i] = 0; 82 } 83 } 84 } 85 int main() 86 { 87 int T; 88 scanf("%d", &T); 89 while (T--) 90 { 91 memset(vis, 0, sizeof(vis)); 92 memset(fial, 0, sizeof(fial)); 93 memset(mp2, 0, sizeof(mp2)); 94 int p = 0; 95 cnt1 = 0; 96 cnt2 = cnt = 0; 97 idx = 0; 98 allans = 0; 99 for (int i = 1; i <= 3; i++) 100 { 101 scanf("%s", mp[i]); 102 int len = strlen(mp[i]); 103 for (int j = 0; j<len; j++) 104 { 105 if (mp[i][j] <= '9'&&mp[i][j] >= '0') 106 { 107 int k = mp[i][j] - '0'; 108 vis[k] = 1; 109 cnt1++; 110 } 111 if (mp[i][j] == '*') 112 cnt++; 113 mp2[idx++] = mp[i][j]; 114 } 115 } 116 cnt2 = 9 - cnt1 - cnt; 117 dfs(0); 118 int k = A(9 - cnt1, cnt); 119 double tt = allans / k * 1.0; 120 printf("%.6lf\n", tt); 121 122 } 123 return 0; 124 }
D. Easy Math 题目传送门
看着题目,说是容易,dalao说这真的容易,菜鸡的我说:不会,下一个吧。 唉,还是菜。。。。。。。
看dalao在群里说过,分析出公式: ,有篇博客也讲到了,地址传送门
1 #include<stdio.h> 2 #include<string.h> 3 #include<algorithm> 4 #include<map> 5 #include<string> 6 #include<math.h> 7 #include<queue> 8 #include<stack> 9 #include<iostream> 10 using namespace std; 11 #define LL long long 12 LL cnt, Cnt, id[1000005], B, m, H[1000005], jud[1000005], Ans, n, w[1000005], pri[1000005], Pri[100005]; 13 bool flag[1000005]; 14 void Primeset(LL n) 15 { 16 LL i, j; 17 for(i=2;i<=n;i++) 18 { 19 if(flag[i]==0) 20 pri[++cnt] = i; 21 for(j=1;j<=cnt&&i*pri[j]<=n;j++) 22 { 23 flag[i*pri[j]] = 1; 24 if(i%pri[j]==0) 25 break; 26 } 27 } 28 } 29 LL F(LL x, LL y) 30 { 31 LL i, k, ans; 32 if(x<=1 || pri[y]>x) 33 return 0; 34 if(x>B) 35 k = n/x; 36 if(x<=B) 37 k = id[x]; 38 ans = (y-1)-H[k]; 39 for(i=1;i<=Cnt;i++) 40 { 41 if(Pri[i]>pri[y-1] && Pri[i]<=w[k]) 42 ans++; 43 } 44 for(i=y;i<=cnt&&(LL)pri[i]*pri[i]<=x;i++) 45 { 46 if(jud[i]==0) 47 ans = ans-F(x/pri[i], i+1); 48 } 49 return ans; 50 } 51 52 int main(void) 53 { 54 LL i, j, k, P, last, sum; 55 scanf("%lld%lld", &n, &P); 56 B = sqrt(n), Primeset(1000002); 57 sum = 0; 58 for(i=1;i<=cnt&&pri[i]*pri[i]<=P;i++) 59 { 60 if(P%(pri[i]*pri[i])==0) 61 { 62 printf("0\n"); 63 return 0; 64 } 65 if(P%pri[i]==0) 66 { 67 jud[i] = 1; 68 Pri[++Cnt] = pri[i], sum++; 69 P /= pri[i]; 70 } 71 } 72 if(P!=1) 73 { 74 Pri[++Cnt] = P, sum++; 75 for(i=1;i<=cnt;i++) 76 { 77 if(pri[i]==P) 78 jud[i] = 1; 79 } 80 } 81 for(i=1;i<=n;i=last+1) 82 { 83 w[++m] = n/i; 84 H[m] = w[m]-1; 85 last = n/(n/i); 86 if(n/i<=B) 87 id[n/i] = m; 88 } 89 for(j=1;j<=cnt;j++) 90 { 91 for(i=1;i<=m&&pri[j]*pri[j]<=w[i];i++) 92 { 93 if(w[i]/pri[j]<=B) 94 k = id[w[i]/pri[j]]; 95 else 96 k = n/(w[i]/pri[j]); 97 H[i] = H[i]-(H[k]-(j-1)); 98 } 99 } 100 Ans = F(n, 1)+1; 101 if(Cnt%2==1) 102 Ans *= -1; 103 printf("%lld\n", Ans); 104 return 0; 105 }
这篇博客讲的挺具体的。传送门
E. End Fantasy VIX 题目传送门
填坑,不会。
F. Features Track 题目传送门
模拟,判断当前的feature在前面连续出现的次数就好然后更新ans 直接暴力。(两个不同代码,供大家参考。
1 #include<cstring> 2 #include<cstdio> 3 #include<iostream> 4 #include<string> 5 #include<queue> 6 #include<vector> 7 #include<algorithm> 8 #include<cmath> 9 #include<set> 10 #include<map> 11 #include<stack> 12 #include<functional> 13 using namespace std; 14 #define clr(a,b) memset(a,b,sizeof(a)) 15 #define lowbit(x) x&-x 16 #define rep(a,b,c) for(ll a=b;a<c;a++) 17 #define dec(a,b,c) for(int a=b;a>c;a--) 18 #define eb(x) emplace_back(x) 19 #define pb(x) push_back(x) 20 #define ps(x) push(x) 21 #define _INIT ios::sync_with_stdio(false);cin.tie(nullptr);cout.precision(10);cout<<fixed 22 #define MAX_N 100000+5 23 #define MAX_M 100 24 typedef long long ll; 25 typedef unsigned long long ull; 26 typedef priority_queue<ll,vector<ll>,greater<ll> >pqg; 27 const ll maxn=1e3; 28 const ll inf=1e7; 29 struct Node 30 { 31 int ti,x,y; 32 }; 33 vector<Node> ve[MAX_N]; 34 int main() 35 { 36 #ifndef ONLINE_JUDGE 37 // freopen("data.txt","r",stdin); 38 #endif 39 //_INIT; 40 int t; 41 scanf("%d",&t); 42 while(t--) 43 { 44 clr(ve,0); 45 int n,ans=0; 46 scanf("%d",&n); 47 for(int i=1; i<=n; i++) 48 { 49 int k;scanf("%d",&k); 50 while(k--) 51 { 52 Node tm;scanf("%d%d",&tm.x,&tm.y);tm.ti=i; 53 for(int j=0;j<ve[i-1].size();j++) 54 { 55 if(ve[i-1][j].x==tm.x&&ve[i-1][j].y==tm.y){tm.ti=ve[i-1][j].ti;break;} 56 } 57 ve[i].push_back(tm); 58 ans=max(ans,i-tm.ti+1); 59 } 60 } 61 printf("%d\n",ans); 62 } 63 return 0; 64 }
1 #include<bits/stdc++.h> 2 using namespace std; 3 4 const int maxn=1e5+5; 5 6 typedef pair<int,int> pii; 7 8 set<pii> G[maxn]; 9 10 int main(){ 11 int t,n,m,a,b,maxl; 12 scanf("%d",&t); 13 for(int e=0;e<t;e++){ 14 maxl=0; 15 for(int i=0;i<maxn;i++)G[i].clear(); 16 scanf("%d",&n); 17 for(int i=0;i<n;i++){ 18 scanf("%d",&m); 19 maxl=max(maxl,m); 20 for(int j=0;j<m;j++){ 21 scanf("%d%d",&a,&b); 22 G[i].insert(pii(a,b)); 23 } 24 } 25 int res=0,t=0; 26 for(int i=0;i<n;i++){ 27 for(set<pii>::iterator j=G[i].begin();j!=G[i].end();j++){ 28 int l=i+1; 29 t=1; 30 while(l<n){ 31 if(G[l].count(*j)){ 32 G[l].erase(*j); 33 l++; 34 t++; 35 res=max(res,t); 36 } 37 else break; 38 } 39 } 40 } 41 printf("%d\n",res); 42 } 43 }
G. Trace 题目传送门
题意:每次给出一个点,然后就会形成两条线,如果后面的矩形覆盖了前面的边,那么这条边就消失了, 最后求剩下的边是多少
思路:分别处理x轴,y轴,然后排序,然后扫过去,每次加上自己的边长以及减去标号比自己小的并且长度比自己高的个数乘自己的边长
1 #include <bits/stdc++.h> 2 using namespace std; 3 4 #define N 50010 5 #define ll long long 6 7 int n; 8 9 struct node 10 { 11 int l, r; 12 int lazy, sum; 13 inline node() {} 14 inline node(int _l, int _r) 15 { 16 l = _l, r = _r; 17 lazy = -1; 18 sum = 0; 19 } 20 }tree[N << 2]; 21 22 inline void pushup(int id) 23 { 24 tree[id].sum = tree[id << 1].sum + tree[id << 1 | 1].sum; 25 } 26 27 inline void pushdown(int id) 28 { 29 if (tree[id].l >= tree[id].r) return; 30 if (~tree[id].lazy) 31 { 32 int lazy = tree[id].lazy; tree[id].lazy = -1; 33 tree[id << 1].lazy = tree[id << 1 | 1].lazy = lazy; 34 tree[id << 1].sum = tree[id << 1 | 1].sum = 0; 35 } 36 } 37 38 inline void build(int id, int l, int r) 39 { 40 tree[id] = node(l, r); 41 if (l == r) return; 42 int mid = (l + r) >> 1; 43 build(id << 1, l, mid); 44 build(id << 1 | 1, mid + 1, r); 45 } 46 47 inline void update(int id, int l, int r, int val) 48 { 49 if (tree[id].l >= l && tree[id].r <= r) 50 { 51 tree[id].sum = val; 52 tree[id].lazy = val; 53 return; 54 } 55 pushdown(id); 56 int mid = (tree[id].l + tree[id].r) >> 1; 57 if (l <= mid) update(id << 1, l, r, val); 58 if (r > mid) update(id << 1 | 1, l, r, val); 59 pushup(id); 60 } 61 62 inline int query(int id, int l, int r) 63 { 64 if (tree[id].l >= l && tree[id].r <= r) return tree[id].sum; 65 pushdown(id); 66 int mid = (tree[id].l + tree[id].r) >> 1; 67 int res = 0; 68 if (l <= mid) res += query(id << 1, l, r); 69 if (r > mid) res += query(id << 1 | 1, l, r); 70 return res; 71 } 72 73 struct DT 74 { 75 int pos; 76 ll x, y; 77 inline void scan(int _pos) 78 { 79 pos = _pos; 80 scanf("%lld%lld", &x, &y); 81 } 82 }arr[N]; 83 84 inline bool cmp1(DT a, DT b) 85 { 86 return a.x < b.x; 87 } 88 89 inline bool cmp2(DT a, DT b) 90 { 91 return a.y < b.y; 92 } 93 94 inline void Run() 95 { 96 while (scanf("%d", &n) != EOF) 97 { 98 for (int i = 1; i <= n; ++i) arr[i].scan(i); 99 build(1, 1, n); 100 sort(arr + 1, arr + 1 + n, cmp1); 101 ll res = 0; 102 for (int i = 1; i <= n; ++i) 103 { 104 res += arr[i].y; 105 int pos = query(1, 1, arr[i].pos); 106 res -= arr[i].y * pos; 107 update(1, 1, arr[i].pos, 0); 108 update(1, arr[i].pos, arr[i].pos, 1); 109 } 110 sort(arr + 1, arr + 1 + n, cmp2); 111 update(1, 1, n, 0); 112 for (int i = 1; i <= n; ++i) 113 { 114 res += arr[i].x; 115 int pos = query(1, 1, arr[i].pos); 116 res -= arr[i].x * pos; 117 update(1, 1, arr[i].pos, 0); 118 update(1, arr[i].pos, arr[i].pos, 1); 119 } 120 printf("%lld\n", res); 121 } 122 } 123 124 int main() 125 { 126 #ifdef LOCAL 127 freopen("Test.in", "r", stdin); 128 #endif 129 130 Run(); 131 return 0; 132 }
栈维护
1 #include <bits/stdc++.h> 2 using namespace std; 3 4 #define N 50010 5 #define ll long long 6 7 int n; 8 9 struct node 10 { 11 int pos; 12 ll x, y; 13 inline void scan(int _pos) 14 { 15 pos = _pos; 16 scanf("%lld%lld", &x, &y); 17 } 18 }arr[N]; 19 20 inline bool cmp1(node a, node b) 21 { 22 return a.x < b.x; 23 } 24 25 inline bool cmp2(node a, node b) 26 { 27 return a.y < b.y; 28 } 29 30 inline void Run() 31 { 32 while (scanf("%d", &n) != EOF) 33 { 34 for (int i = 1; i <= n; ++i) arr[i].scan(i); 35 sort(arr + 1, arr + 1 + n, cmp1); 36 ll res = 0; 37 stack<int>s; 38 for (int i = 1; i <= n; ++i) 39 { 40 res += arr[i].y; 41 int cnt = 0; 42 while (!s.empty() && s.top() < arr[i].pos) 43 { 44 cnt++; 45 s.pop(); 46 } 47 res -= cnt * arr[i].y; 48 s.push(arr[i].pos); 49 } 50 while (!s.empty()) 51 { 52 s.pop(); 53 } 54 sort(arr + 1, arr + 1 + n, cmp2); 55 for (int i = 1; i <= n; ++i) 56 { 57 res += arr[i].x; 58 int cnt = 0; 59 while (!s.empty() && s.top() < arr[i].pos) 60 { 61 cnt++; 62 s.pop(); 63 } 64 res -= cnt * arr[i].x; 65 s.push(arr[i].pos); 66 } 67 printf("%lld\n", res); 68 } 69 } 70 71 int main() 72 { 73 #ifdef LOCAL_JUDGE 74 freopen("Text.txt", "r", stdin); 75 #endif 76 77 Run(); 78 return 0; 79 }
还有bin巨巨的暴力解法,真牛皮!链接
H. Ryuji doesn't want to study 题目传送门
这题本来就是一个裸题,有一个点没考虑坑了我三小时,气死我了,真心太菜!
算一个两个不同的后缀和就行,我是强行前缀和的。
代码如下:(树状数组或者线段树,裸写)
1 #include<bits/stdc++.h> 2 using namespace std; 3 typedef long long ll; 4 ll c[100010],a[100005],c1[100005]; 5 ll n; 6 7 ll lowbit(ll x) 8 { 9 return x&(~x+1); 10 } 11 void Add(ll x,ll d) 12 { 13 while(x<=n) 14 { 15 c[x]+=d; 16 x+=lowbit(x); 17 } 18 } 19 ll sum(ll x) 20 { 21 ll ret=0; 22 while(x>=1) 23 { 24 ret+=c[x]; 25 x-=lowbit(x); 26 } 27 return ret; 28 } 29 void Add1(ll x,ll d) 30 { 31 while(x<=n) 32 { 33 c1[x]+=d; 34 x+=lowbit(x); 35 } 36 } 37 ll sum1(ll x) 38 { 39 ll ret1=0; 40 while(x>=1) 41 { 42 ret1+=c1[x]; 43 x-=lowbit(x); 44 } 45 return ret1; 46 } 47 int main() 48 { 49 ll m; 50 ios::sync_with_stdio(false); 51 cin.tie(0); 52 while(cin>>n>>m) 53 { 54 for(ll i=1; i<=n; i++) 55 { 56 //scanf("%lld",&a[i]); 57 cin>>a[i]; 58 Add(i,a[i]*(n-i+1)); 59 Add1(i,a[i]); 60 } 61 while(m--) 62 { 63 ll num; 64 cin>>num; 65 //scanf("%d",&num); 66 if(num==2) 67 { 68 ll x,k; 69 cin>>x>>k; 70 71 //scanf("%lld%lld",&x,&k); 72 Add(x,(k-a[x])*(n-x+1)); 73 Add1(x,k-a[x]);a[x]=k; 74 } 75 else if(num==1) 76 { 77 ll x,y; 78 //scanf("%lld%lld",&x,&y); 79 cin>>x>>y; 80 printf("%lld\n",sum(y)-sum(x-1)-(sum1(y)-sum1(x-1))*(n-y)); 81 } 82 } 83 } 84 return 0; 85 }
I. Characters with Hash 题目传送门
不想说了,也是坑了我两发,没有考虑字符串前几个字符与L字符都相同的情况。考虑步骤,刷Codeforces太少了。又懒又菜!!!
1 #include<bits/stdc++.h> 2 using namespace std; 3 4 int main() 5 { 6 int n,q,p,b,c,i,j; 7 double a[100005],ans=0; 8 scanf("%d%d",&n,&q); 9 for(int i=0; i<n; i++) 10 scanf("%lf",&a[i]); 11 while(q--) 12 { 13 scanf("%d%d%d",&p,&b,&c); 14 ans=0; 15 int L=c-b+1; 16 switch(p) 17 { 18 case 1: 19 for(i=b-1; i<c; i++) 20 ans+=a[i]*(L--); 21 printf("%.0f\n",ans); 22 break; 23 case 2: 24 a[b-1]=c; 25 break; 26 } 27 } 28 return 0; 29 }
J. Maze Designer 题目传送门 最大生成树+LCA
可以把每个格点视作视作图的点,隔开两点的边视作图的边,则构建迷宫可以视作求其生成树,剩余的边就是组成迷宫的墙.因为要花费最小,所以使删去的墙权置最大即可,呢么就是求最大生成树即可.
然后每次查询相当于查这个最大生成树上任意两点的最短距离,到这一步就是个LCA板子题了.
所以:最大生成树+树上两点最短距离。
表示我也不会lca,是时候去学习一波了。图:留下了没有技术的泪水!
1 #include <iostream> 2 #include <vector> 3 #include <cstdio> 4 #include <string> 5 #include <cstring> 6 #include <map> 7 #include <algorithm> 8 #include <queue> 9 #include <set> 10 #include <cmath> 11 #include <sstream> 12 #include <stack> 13 #include <fstream> 14 #include <ctime> 15 #pragma warning(disable:4996); 16 #define mem(sx,sy) memset(sx,sy,sizeof(sx)) 17 typedef long long ll; 18 typedef unsigned long long ull; 19 const double eps = 1e-8; 20 const double PI = acos(-1.0); 21 const ll llINF = 0x3f3f3f3f3f3f3f3f; 22 const int INF = 0x3f3f3f3f; 23 using namespace std; 24 //#define pa pair<int, int> 25 //const int mod = 1e9 + 7; 26 const int maxn = 1000005; 27 const int maxq = 300005; 28 struct node { 29 int u, v, w, next, lca; 30 }; 31 32 struct LCA { 33 node edges[maxn], ask[maxq]; 34 int ghead[maxn], gcnt, ahead[maxn], acnt; 35 int anc[maxn]; 36 int vis[maxn]; 37 ll dist[maxn]; 38 int fa[maxn]; 39 40 void addedge(int u, int v, int w) { 41 edges[gcnt].v = v; 42 edges[gcnt].w = w; 43 edges[gcnt].next = ghead[u]; 44 ghead[u] = gcnt++; 45 } 46 47 void addask(int u, int v) { 48 ask[acnt].u = u; 49 ask[acnt].v = v; 50 ask[acnt].next = ahead[u]; 51 ahead[u] = acnt++; 52 } 53 54 void init() { 55 mem(vis, 0); 56 mem(ghead, -1); 57 mem(ahead, -1); 58 gcnt = 0; 59 acnt = 0; 60 } 61 62 int Find(int x) { 63 return fa[x] == x ? x : (fa[x] = Find(fa[x])); 64 } 65 66 void getLCA(int u, int d) { 67 dist[u] = d; 68 fa[u] = u; 69 vis[u] = 1; 70 for (int i = ghead[u]; i != -1; i = edges[i].next) { 71 int v = edges[i].v; 72 if (!vis[v]) { 73 getLCA(v, d + edges[i].w); 74 fa[v] = u; 75 anc[fa[v]] = u; 76 } 77 } 78 for (int i = ahead[u]; i != -1; i = ask[i].next) { 79 int v = ask[i].v; 80 if (vis[v]) 81 ask[i].lca = ask[i ^ 1].lca = Find(ask[i].v); 82 } 83 84 } 85 86 }L; 87 88 struct edge { 89 int u, v; 90 ll w; 91 bool operator<(const edge &e)const { return w>e.w; } 92 edge(int _u = 0, int _v = 0, ll _w = 0) 93 :u(_u), v(_v), w(_w) {} 94 }; 95 96 struct Kruskal { 97 int n, m; 98 edge edges[maxn]; 99 int fa[maxn]; 100 int Find(int x) { 101 return fa[x] == -1 ? x : fa[x] = Find(fa[x]); 102 } 103 void init(int _n) { 104 this->n = _n; 105 m = 0; 106 mem(fa, -1); 107 } 108 109 void AddEdge(int u, int v, ll dist) { 110 edges[m++] = edge(u, v, dist); 111 } 112 113 ll kruskal() { 114 ll sum = 0; 115 int cntnum = 0; 116 sort(edges, edges + m); 117 for (int i = 0; i < m; i++) { 118 int u = edges[i].u, v = edges[i].v; 119 if (Find(u) != Find(v)) { 120 L.addedge(u, v, 1); 121 L.addedge(v, u, 1); 122 //cout << u << " " << v << endl; 123 sum += edges[i].w; 124 fa[Find(u)] = Find(v); 125 if (++cntnum >= n - 1) return sum; 126 } 127 } 128 return -1; 129 } 130 }G; 131 132 int main() { 133 int n, m; 134 while (~scanf("%d%d", &n, &m)) { 135 G.init(n*m); 136 L.init(); 137 for (int i = 1; i <= n; ++i) { 138 for (int j = 1; j <= m; ++j) { 139 int w1, w2; char c1, c2; 140 scanf(" %c%d %c%d", &c1, &w1, &c2, &w2); 141 if (c1 == 'D') { 142 G.AddEdge((i - 1)*m + j, i*m + j, w1); 143 } 144 if (c2 == 'R') { 145 G.AddEdge((i - 1)*m + j, (i - 1)*m + j + 1, w2); 146 } 147 } 148 } 149 G.kruskal(); 150 int q; 151 scanf("%d", &q); 152 for (int i = 1, x1, x2, y1, y2; i <= q; i++) { 153 scanf("%d%d%d%d", &x1, &y1, &x2, &y2); 154 int u = (x1 - 1)*m + y1; 155 int v = (x2 - 1)*m + y2; 156 L.addask(u, v); 157 L.addask(v, u); 158 } 159 L.getLCA(1, 0); 160 for (int i = 0; i < L.acnt; i += 2) { 161 printf("%lld\n", L.dist[L.ask[i].u] + L.dist[L.ask[i].v] - 2 * L.dist[L.ask[i].lca]); 162 } 163 } 164 }
K. Morgana Net 题目传送门
矩阵快速幂 dalao的分析如下
1 #include<bits/stdc++.h> 2 using namespace std; 3 4 int T,n,m,t; 5 int a[20][20],b[20][20]; 6 7 struct Matrix 8 { 9 int n,m,d[70][70]; 10 Matrix (int N=0, int M=0) 11 { 12 n = N, m = M; 13 memset(d,0,sizeof(d)); 14 } 15 friend Matrix operator * (const Matrix &a, const Matrix &b) 16 { 17 Matrix c(a.n,b.m); 18 for (int i=0;i<a.n;i++) 19 for (int j=0;j<b.m;j++) 20 { 21 long long tmp = 0; 22 for (int k=0;k<a.m;k++) 23 tmp += (a.d[i][k]*b.d[k][j] & 1); 24 c.d[i][j] = tmp & 1; 25 } 26 return c; 27 } 28 }; 29 30 void solve() 31 { 32 Matrix A(1,n*n),B(n*n,n*n); 33 m = m/2; 34 for (int i=0;i<n;i++) 35 for (int j=0;j<n;j++) 36 { 37 A.d[0][i*n+j] = a[i][j] & 1; 38 for (int p = i-m; p <= i+m; p++) 39 for (int q = j-m; q <= j+m; q++) 40 { 41 if (p < 0 || q < 0 || p >= n || q >= n) continue; 42 B.d[p*n+q][i*n+j] = b[p-i+m][q-j+m] & 1; 43 } 44 } 45 46 while (t) 47 { 48 if (t & 1) A = A*B; 49 B = B*B; 50 t = t>>1; 51 } 52 int ans = 0; 53 for (int i=0;i<n*n;i++) ans += A.d[0][i]; 54 printf("%d\n",ans); 55 return; 56 } 57 58 int main() 59 { 60 scanf("%d",&T); 61 while (T--) 62 { 63 scanf("%d %d %d",&n,&m,&t); 64 for (int i=0;i<n;i++) 65 for (int j=0;j<n;j++) scanf("%d",&a[i][j]); 66 for (int i=0;i<m;i++) 67 for (int j=0;j<m;j++) scanf("%d",&b[i][j]); 68 solve(); 69 } 70 return 0; 71 }
这次比赛打完之后,整个人都是崩溃的,这场的题目很好,坑点很多,前面两道签到题目我都是签了一个小时多,我无语了。感觉自己的练习题量特少,每天感觉都是浑浑噩噩的过着,都不知道自己在干啥,大四了,感觉太浪了,需要冷静下来想想,接下来要学习什么东西。别一天到晚东学一个算法西学一个小程序,感觉自己没有规划,一天到晚漫无目的的过着。
接下来还是老老实实学习算法吧,每天坚持刷题。学习微信小程序的全栈开发。(估计没什么机会去参加比赛了。。。。自己上半年和暑期都没有刷题。。。。。太菜了QAQ。别为自己的菜找理由,埋下头来学习就行,别浪!。
终于写完了,溜了溜了。