这里会显示出您选择的修订版和当前版本之间的差别。
后一修订版 | 前一修订版 | ||
2020-2021:teams:die_java:front_page_summertrain2 [2020/07/17 15:26] fyhssgss 创建 |
2020-2021:teams:die_java:front_page_summertrain2 [2020/10/17 23:02] (当前版本) fyhssgss |
||
---|---|---|---|
行 5: | 行 5: | ||
===== 训练结果 ===== | ===== 训练结果 ===== | ||
- | * 时间:2020-7-13 12:00~17:00 | + | * 时间:''2020-7-13 12:00~17:00'' |
- | * rank:145/1159 | + | * rank:''145/1159'' |
- | * 完成情况:4/8/11 | + | * 完成情况:''4/8/11'' |
===== 题解 ===== | ===== 题解 ===== | ||
- | ===== 题目名字 ===== | + | ===== B.Boundary ===== |
=== 题意 === | === 题意 === | ||
+ | |||
+ | 给了n个点,画一个过原点的圆,问最多能有多少个点在圆上。 | ||
=== 题解 === | === 题解 === | ||
+ | 我们固定原点和一个点,枚举剩下的点,求出这三个点的圆心,答案即为重合最多的圆心数加一。题目有点卡常,用分数计算会超时,无奈只能用double记录点玄学通过。 | ||
+ | |||
+ | <hidden 代码> | ||
<code cpp> | <code cpp> | ||
+ | #include<bits/stdc++.h> | ||
+ | using namespace std; | ||
+ | #define mem(a,b) memset(a,b,sizeof(a)) | ||
+ | typedef long long LL; | ||
+ | typedef pair<LL,LL> PII; | ||
+ | typedef pair<double,double> PDD; | ||
+ | #define X first | ||
+ | #define Y second | ||
+ | inline int read() | ||
+ | { | ||
+ | int x=0,f=1;char c=getchar(); | ||
+ | while(!isdigit(c)){if(c=='-')f=-1;c=getchar();} | ||
+ | while(isdigit(c)){x=x*10+c-'0';c=getchar();} | ||
+ | return x*f; | ||
+ | } | ||
+ | const int N=2000055; | ||
+ | const int maxn=2010; | ||
+ | PII A[maxn]; | ||
+ | LL aa[N]; | ||
+ | int n,ans,sum; | ||
+ | map<PDD,int> mp; | ||
+ | LL gcd(LL a,LL b){return b==0 ? a : gcd(b,a%b);} | ||
+ | int main() | ||
+ | { | ||
+ | n=read(); | ||
+ | for(int i=1;i<=n;i++)scanf("%lld%lld",&A[i].X,&A[i].Y); | ||
+ | for(int i=1;i<n;i++) | ||
+ | { | ||
+ | mp.clear(); | ||
+ | for(int j=i+1;j<=n;j++) | ||
+ | { | ||
+ | LL a=A[i].X,b=A[i].Y,c=A[j].X,d=A[j].Y; | ||
+ | if(b*c-a*d==0) continue; | ||
+ | LL p=a*a+b*b,q=c*c+d*d,r=b*c-a*d; | ||
+ | LL x1=q*b-p*d,x2=r; | ||
+ | LL y1=p*c-q*a,y2=r; | ||
+ | // LL xx=gcd(abs(x1),abs(x2)),yy=gcd(abs(y1),abs(y2)); | ||
+ | double xx=1.*x1/x2; | ||
+ | double yy=1.*y1/y2; | ||
+ | /* if(x1<0) 分数做法 | ||
+ | { | ||
+ | x1*=-1;x2*=-1; | ||
+ | } | ||
+ | else if(x1==0) | ||
+ | { | ||
+ | x2=1;xx=1; | ||
+ | } | ||
+ | if(y1<0) | ||
+ | { | ||
+ | y1*=-1;y2*=-1; | ||
+ | } | ||
+ | else if(y1==0) | ||
+ | { | ||
+ | y2=1;yy=1; | ||
+ | } | ||
+ | x1/=xx;x2/=xx;y1/=yy;y2/=yy; | ||
+ | LL hs2=0; | ||
+ | hs2=hs2*998244353+x1;hs2=hs2*998244353+x2; | ||
+ | hs2=hs2*998244353+y1;hs2=hs2*998244353+y2; | ||
+ | // printf("%d %d %lld %lld %lld %lld\n",i,j,x1,x2,y1,y2); | ||
+ | // aa[++sum]=hs2;*/ | ||
+ | ans=max(ans,++mp[PDD(xx,yy)]); | ||
+ | } | ||
+ | } | ||
+ | /* sort(aa+1,aa+1+sum); | ||
+ | for(int i=1;i<=sum;i++) | ||
+ | { | ||
+ | int tot=1; | ||
+ | for(int j=i+1;j<=sum;j++) | ||
+ | { | ||
+ | if(aa[j]==aa[i]) tot++; | ||
+ | else break; | ||
+ | } | ||
+ | ans=max(ans,tot); | ||
+ | i+=tot-1; | ||
+ | }*/ | ||
+ | printf("%d\n",++ans); | ||
+ | return 0; | ||
+ | } | ||
</code> | </code> | ||
+ | </hidden> | ||
+ | ===== C.Cover the Tree ===== | ||
+ | |||
+ | === 题意 === | ||
+ | |||
+ | 用尽量少的路径覆盖一棵树的所有边 | ||
+ | |||
+ | === 题解 === | ||
+ | |||
+ | solved by hxm | ||
+ | |||
+ | 路径显然最优时从一个叶子出发,到另一个叶子结束。记叶子节点个数为$m$,那么答案应该就是$\lceil \frac{m}{2} \rceil$ | ||
+ | |||
+ | 问题是如何找到一组解 | ||
+ | |||
+ | 选一个点作为根节点,如果能将不同子树里的叶子匹配,就能做到完全覆盖。那么只需要每次选剩余叶子最多的两个子树匹配。 | ||
+ | |||
+ | 容易发现,这样操作,只需要最大的子树里叶子节点个数不超过总个数的一半。 | ||
+ | |||
+ | 只需要随意选一个点,如果不满足条件,就往那个叶子最多的子树走,最后一定能走到一个合法的点。 | ||
+ | |||
+ | <hidden 代码> | ||
+ | <code cpp> | ||
+ | #include<algorithm> | ||
+ | #include<iostream> | ||
+ | #include<cstdlib> | ||
+ | #include<cstring> | ||
+ | #include<cstdio> | ||
+ | #include<vector> | ||
+ | #include<queue> | ||
+ | #include<cmath> | ||
+ | #include<map> | ||
+ | #include<set> | ||
+ | #define LL long long int | ||
+ | #define REP(i,n) for (int i = 1; i <= (n); i++) | ||
+ | #define Redge(u) for (int k = h[u],to; k; k = ed[k].nxt) | ||
+ | #define cls(s,v) memset(s,v,sizeof(s)) | ||
+ | #define mp(a,b) make_pair<int,int>(a,b) | ||
+ | #define cp pair<int,int> | ||
+ | using namespace std; | ||
+ | const int maxn = 200005,maxm = 400005,INF = 0x3f3f3f3f; | ||
+ | inline int read(){ | ||
+ | int out = 0,flag = 1; char c = getchar(); | ||
+ | while (c < 48 || c > 57){if (c == '-') flag = 0; c = getchar();} | ||
+ | while (c >= 48 && c <= 57){out = (out << 1) + (out << 3) + c - 48; c = getchar();} | ||
+ | return flag ? out : -out; | ||
+ | } | ||
+ | int n,h[maxn],ne,de[maxn]; | ||
+ | struct EDGE{ | ||
+ | int to,nxt; | ||
+ | }ed[maxm]; | ||
+ | void build(int u,int v){ | ||
+ | ed[++ne] = (EDGE){v,h[u]}; h[u] = ne; | ||
+ | ed[++ne] = (EDGE){u,h[v]}; h[v] = ne; | ||
+ | de[u]++; de[v]++; | ||
+ | } | ||
+ | int siz[maxn],rt,tot; | ||
+ | void dfs1(int u,int ff){ | ||
+ | if (de[u] == 1) siz[u] = 1; | ||
+ | else { | ||
+ | Redge(u) if ((to = ed[k].to) != ff){ | ||
+ | dfs1(to,u); | ||
+ | siz[u] += siz[to]; | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | void dfs2(int u,int ff){ | ||
+ | int flag = 1; | ||
+ | Redge(u) if ((to = ed[k].to) != ff){ | ||
+ | if (siz[to] * 2 > tot){ | ||
+ | flag = 0; | ||
+ | dfs2(to,u); | ||
+ | } | ||
+ | if (!flag) break; | ||
+ | } | ||
+ | if (flag) rt = u; | ||
+ | } | ||
+ | int m,pos[maxn],len[maxn]; | ||
+ | vector<int> leaf[maxn]; | ||
+ | struct node{ | ||
+ | int i; | ||
+ | }; | ||
+ | inline bool operator <(const node& a,const node& b){ | ||
+ | return len[a.i] - pos[a.i] < len[b.i] - pos[b.i]; | ||
+ | } | ||
+ | priority_queue<node> q; | ||
+ | void dfs3(int u,int ff){ | ||
+ | if (de[u] == 1) leaf[m].push_back(u),len[m]++; | ||
+ | else { | ||
+ | Redge(u) if ((to = ed[k].to) != ff){ | ||
+ | dfs3(to,u); | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | int main(){ | ||
+ | n = read(); | ||
+ | if (n == 1){printf("1\n1 1\n"); return 0;} | ||
+ | if (n == 2){printf("1\n1 2\n"); return 0;} | ||
+ | for (int i = 1; i < n; i++) build(read(),read()); | ||
+ | for (int i = 1; i <= n; i++){ | ||
+ | if (de[i] == 1) tot++; | ||
+ | else rt = i; | ||
+ | } | ||
+ | dfs1(rt,0); | ||
+ | dfs2(rt,0); | ||
+ | //cout << rt << endl; | ||
+ | Redge(rt){ | ||
+ | m++; | ||
+ | dfs3(to = ed[k].to,rt); | ||
+ | } | ||
+ | //REP(i,m) cout << len[i] << endl; | ||
+ | REP(i,m) q.push((node){i}); | ||
+ | printf("%d\n",(tot + 1) / 2); | ||
+ | int cnt = 0,a,b; | ||
+ | while (tot - cnt > 1){ | ||
+ | a = q.top().i; q.pop(); | ||
+ | b = q.top().i; q.pop(); | ||
+ | printf("%d %d\n",leaf[a][pos[a]++],leaf[b][pos[b]++]); | ||
+ | if (pos[a] < len[a]) q.push((node){a}); | ||
+ | if (pos[b] < len[b]) q.push((node){b}); | ||
+ | cnt += 2; | ||
+ | } | ||
+ | if (tot & 1){ | ||
+ | a = q.top().i; | ||
+ | printf("%d %d\n",leaf[a][pos[a]++],rt); | ||
+ | } | ||
+ | return 0; | ||
+ | } | ||
+ | </code> | ||
+ | </hidden> | ||
+ | |||
+ | ===== D.Duration ===== | ||
+ | solved by hxm | ||
+ | 水题 | ||
+ | |||
+ | ===== E.Exclusive OR ===== | ||
+ | |||
+ | === 题意 === | ||
+ | |||
+ | 给了 $n$ 个数,让你求 $1 \le i \le n$ ,选 $i$ 个数(可以选相同的数)异或和的最大值。 | ||
+ | |||
+ | === 题解 === | ||
+ | |||
+ | 发现 $i$ 在19之后答案和 $i-2$ 一致,原理参考线性基。所以我们只需求前19个的答案,用FWT即可完成。 | ||
+ | |||
+ | <hidden 代码> | ||
+ | <code cpp> | ||
+ | #include<iostream> | ||
+ | #include<cstdio> | ||
+ | #include<algorithm> | ||
+ | #include<cstring> | ||
+ | #define ll long long | ||
+ | using namespace std; | ||
+ | int read() | ||
+ | { | ||
+ | int k=0,f=1;char c=getchar(); | ||
+ | for(;!isdigit(c);c=getchar()) if(c=='-') f=-1; | ||
+ | for(;isdigit(c);c=getchar()) k=k*10+c-'0';return k*f; | ||
+ | } | ||
+ | const int M=1050000; | ||
+ | int n,N,a[M],b[M],c[M],ans[M]; | ||
+ | void FWT(int *a,int opt) | ||
+ | { | ||
+ | for(int i=1;i<N;i<<=1) | ||
+ | for(int p=i<<1,j=0;j<N;j+=p) | ||
+ | for(int k=0;k<i;++k) | ||
+ | { | ||
+ | int X=a[j+k],Y=a[i+j+k]; | ||
+ | a[j+k]=(X+Y);a[i+j+k]=(X-Y); | ||
+ | if(opt==-1)a[j+k]=1ll*a[j+k]/2,a[i+j+k]=1ll*a[i+j+k]/2; | ||
+ | } | ||
+ | } | ||
+ | int main() | ||
+ | { | ||
+ | n=read();int mx=0,x; | ||
+ | for(int i=1;i<=n;i++) | ||
+ | { | ||
+ | x=read(); | ||
+ | a[x]=1;b[x]=1;mx=max(mx,x); | ||
+ | } | ||
+ | for(N=1;N<=mx;N<<=1); | ||
+ | ans[1]=mx; | ||
+ | FWT(b,1); | ||
+ | for(int i=2;i<=min(25,n);i++) | ||
+ | { | ||
+ | for(int j=0;j<N;j++) | ||
+ | if(a[j]) a[j]=1; | ||
+ | FWT(a,1); | ||
+ | for(int j=0;j<N;j++) | ||
+ | a[j]=a[j]*b[j]; | ||
+ | FWT(a,-1); | ||
+ | for(int j=N-1;j>=0;j--) | ||
+ | { | ||
+ | if(a[j]) {ans[i]=j;break;} | ||
+ | } | ||
+ | // for(int j=0;j<N;j++) | ||
+ | // cout<<a[j]<<" "; | ||
+ | // cout<<endl; | ||
+ | } | ||
+ | for(int i=1;i<=n;i++) | ||
+ | { | ||
+ | if(i>25) | ||
+ | { | ||
+ | if(i&1) printf("%d ",ans[25]); | ||
+ | else printf("%d ",ans[24]); | ||
+ | } | ||
+ | else printf("%d ",ans[i]); | ||
+ | } | ||
+ | puts(""); | ||
+ | return 0; | ||
+ | } | ||
+ | </code> | ||
+ | </hidden> | ||
+ | ===== F.Fake Maxpooling ===== | ||
+ | |||
+ | === 题意 === | ||
+ | |||
+ | 一个$n \times m$的网格,每个格子$(x,y)$里写着$lcm(x,y)$。 | ||
+ | |||
+ | 现在用一个$k \times k$的框去选中一些格子,得到其中最大值。 | ||
+ | |||
+ | 求所有选取方法最大值的总和。 | ||
+ | |||
+ | === 题解 === | ||
+ | |||
+ | solved by hxm | ||
+ | |||
+ | 暴力$O(nmlogn)$求出$lcm$,然后竖着用$m$个单调队列维护最大值,然后再用一个单调队列维护单调队列的最大值,即可求出当前区域的最大值。 | ||
+ | |||
+ | <hidden 代码> | ||
+ | <code cpp> | ||
+ | #include<algorithm> | ||
+ | #include<iostream> | ||
+ | #include<cstdlib> | ||
+ | #include<cstring> | ||
+ | #include<cstdio> | ||
+ | #include<vector> | ||
+ | #include<queue> | ||
+ | #include<cmath> | ||
+ | #include<map> | ||
+ | #include<set> | ||
+ | #define LL long long int | ||
+ | #define REP(i,n) for (int i = 1; i <= (n); i++) | ||
+ | #define Redge(u) for (int k = h[u],to; k; k = ed[k].nxt) | ||
+ | #define cls(s,v) memset(s,v,sizeof(s)) | ||
+ | #define mp(a,b) make_pair<int,int>(a,b) | ||
+ | #define cp pair<int,int> | ||
+ | using namespace std; | ||
+ | const int maxn = 5005,maxm = 100005,INF = 0x3f3f3f3f; | ||
+ | inline int read(){ | ||
+ | int out = 0,flag = 1; char c = getchar(); | ||
+ | while (c < 48 || c > 57){if (c == '-') flag = 0; c = getchar();} | ||
+ | while (c >= 48 && c <= 57){out = (out << 1) + (out << 3) + c - 48; c = getchar();} | ||
+ | return flag ? out : -out; | ||
+ | } | ||
+ | int gcd(int a,int b) { | ||
+ | return !b ? a : gcd(b,a % b); | ||
+ | } | ||
+ | int A[maxn][maxn],n,m,K; | ||
+ | int Q[maxn][maxn],H[maxn],T[maxn]; | ||
+ | int q[maxn],pos[maxn],head,tail; | ||
+ | int main(){ | ||
+ | n = read(); m = read(); K = read(); | ||
+ | REP(i,n) REP(j,m) A[i][j] = i * j / gcd(i,j); | ||
+ | REP(i,m) H[i] = 1; | ||
+ | LL ans = 0; | ||
+ | for (int i = 1; i <= n; i++){ | ||
+ | for (int j = 1; j <= m; j++){ | ||
+ | while (H[j] <= T[j] && i - Q[j][H[j]] >= K) H[j]++; | ||
+ | while (T[j] >= H[j] && A[i][j] >= A[Q[j][T[j]]][j]) T[j]--; | ||
+ | Q[j][++T[j]] = i; | ||
+ | } | ||
+ | if (i >= K){ | ||
+ | head = 1; tail = 0; | ||
+ | for (int j = 1; j <= m; j++){ | ||
+ | while (head <= tail && j - pos[head] >= K) head++; | ||
+ | while (head <= tail && A[Q[j][H[j]]][j] >= q[tail]) tail--; | ||
+ | q[++tail] = A[Q[j][H[j]]][j]; | ||
+ | pos[tail] = j; | ||
+ | if (j >= K) ans += q[head]; | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | printf("%lld\n",ans); | ||
+ | return 0; | ||
+ | } | ||
+ | </code> | ||
+ | </hidden> | ||
+ | |||
===== H.Happy Triangle ===== | ===== H.Happy Triangle ===== | ||
行 31: | 行 404: | ||
=== 题解 === | === 题解 === | ||
+ | |||
+ | 补题 by fyh | ||
询问即问是否存在两个数$a,b$,使得$|a-b|<x<a+b$。这个很明显是一个区间覆盖问题,但是因为集合中两两组成的区间是$n^2$级别的,考虑减少区间:$a>b>c$,其中$(a,b)$与$(a,c)$组成的开区间分别是$(a-b,a+b),(a-c,a+c)$。后者是完全被前者包含的,所以对于每一个数,只需要找他的前驱,用线段树维护一下这$n$个区间的并即可。 | 询问即问是否存在两个数$a,b$,使得$|a-b|<x<a+b$。这个很明显是一个区间覆盖问题,但是因为集合中两两组成的区间是$n^2$级别的,考虑减少区间:$a>b>c$,其中$(a,b)$与$(a,c)$组成的开区间分别是$(a-b,a+b),(a-c,a+c)$。后者是完全被前者包含的,所以对于每一个数,只需要找他的前驱,用线段树维护一下这$n$个区间的并即可。 | ||
+ | <hidden 代码> | ||
<code cpp> | <code cpp> | ||
#include<bits/stdc++.h> | #include<bits/stdc++.h> | ||
行 163: | 行 539: | ||
} | } | ||
</code> | </code> | ||
- | ===== 题目名字 ===== | + | </hidden> |
- | === 题意 === | ||
- | |||
- | === 题解 === | ||
- | |||
- | <code cpp> | ||
- | |||
- | </code> | ||
===== J.Just Shuffle ===== | ===== J.Just Shuffle ===== | ||
行 179: | 行 548: | ||
=== 题解 === | === 题解 === | ||
+ | solved by fyh | ||
本题的一大特性是$k$是质数,也就是$k$模任何数都非0。 | 本题的一大特性是$k$是质数,也就是$k$模任何数都非0。 | ||
行 184: | 行 554: | ||
置换其实就是若干个循环。每个循环都是独立的,现考虑某个长度为$size$的环,置换$k$次的结果是等效于置换为$k\%size$的结果。设$k\%size=m$,则我们当前得到的环其实是走$m$步的结果,我们要得到走1步的结果,便可以考虑在这个环上每步都好几倍,最后等效为走一步,即解$m*k\%size=1$的模方程的$x$。至此,我们成功构造出了原置换。 | 置换其实就是若干个循环。每个循环都是独立的,现考虑某个长度为$size$的环,置换$k$次的结果是等效于置换为$k\%size$的结果。设$k\%size=m$,则我们当前得到的环其实是走$m$步的结果,我们要得到走1步的结果,便可以考虑在这个环上每步都好几倍,最后等效为走一步,即解$m*k\%size=1$的模方程的$x$。至此,我们成功构造出了原置换。 | ||
+ | <hidden 代码> | ||
<code cpp> | <code cpp> | ||
#include<bits/stdc++.h> | #include<bits/stdc++.h> | ||
行 237: | 行 608: | ||
} | } | ||
</code> | </code> | ||
+ | </hidden> | ||
+ | |||
+ | ===== I.Interval ===== | ||
+ | |||
+ | === 题意 === | ||
+ | |||
+ | 对一个区间$[l,r]$可进行两种操作: | ||
+ | |||
+ | 1、将$[l,r]$变为$[l-1,r]$或$[l+1,r]$ | ||
+ | |||
+ | 2、将$[l,r]$变为$[l,r-1]$或$[l,r+1]$ | ||
+ | |||
+ | 现在有$m$个限制,限制区间$[l_i,r_i]$不能进行操作$c$($c=L$或$c=R$),但是开启这个限制需要$w_i$的费用 | ||
+ | |||
+ | 问最少的费用花费,使得区间$[1,n]$不能转移到任意一个区间$[l,r]$使$l=r$ | ||
+ | |||
+ | === 题解 === | ||
+ | 补题 solved by hxm | ||
+ | |||
+ | 将每个区间看做二维平面上的点,我们的目标就是阻止从$(1,n)$走到任意一个$(x,x)$ | ||
+ | |||
+ | 显然相邻的点可以连边,我们把$(1,n)$看做源点的话,新建一个汇点将所有$(x,x)$连向汇点,那么这就是一个最小割问题 | ||
+ | |||
+ | 但是会T。 | ||
+ | |||
+ | 发现这是一个平面图,转化为对偶图的最短路即可 | ||
+ | |||
+ | <hidden 代码> | ||
+ | <code cpp> | ||
+ | #include<algorithm> | ||
+ | #include<iostream> | ||
+ | #include<cstdlib> | ||
+ | #include<cstring> | ||
+ | #include<cstdio> | ||
+ | #include<vector> | ||
+ | #include<queue> | ||
+ | #include<cmath> | ||
+ | #include<map> | ||
+ | #include<set> | ||
+ | #define LL long long int | ||
+ | #define REP(i,n) for (int i = 1; i <= (n); i++) | ||
+ | #define Redge(u) for (int k = h[u],to; k; k = ed[k].nxt) | ||
+ | #define cls(s,v) memset(s,v,sizeof(s)) | ||
+ | #define mp(a,b) make_pair<int,int>(a,b) | ||
+ | #define cp pair<int,int> | ||
+ | using namespace std; | ||
+ | const int maxn = 250005,maxm = 100005; | ||
+ | const LL INF = 1000000000000000000ll; | ||
+ | inline int read(){ | ||
+ | int out = 0,flag = 1; char c = getchar(); | ||
+ | while (c < 48 || c > 57){if (c == '-') flag = 0; c = getchar();} | ||
+ | while (c >= 48 && c <= 57){out = (out << 1) + (out << 3) + c - 48; c = getchar();} | ||
+ | return flag ? out : -out; | ||
+ | } | ||
+ | int h[maxn],ne; | ||
+ | struct EDGE{ | ||
+ | int to,w,nxt; | ||
+ | }ed[maxn * 2]; | ||
+ | void build(int u,int v,int w){ | ||
+ | ed[++ne] = (EDGE){v,w,h[u]}; h[u] = ne; | ||
+ | ed[++ne] = (EDGE){u,w,h[v]}; h[v] = ne; | ||
+ | //printf("build %d to %d costs %d\n",u,v,w); | ||
+ | } | ||
+ | int C[505][505],R[505][505]; | ||
+ | int n,m,S,T; | ||
+ | int id(int x,int y){ | ||
+ | return x * (x - 1) / 2 + y; | ||
+ | } | ||
+ | LL d[maxn],vis[maxn]; | ||
+ | struct node{int u; LL d;}; | ||
+ | inline bool operator <(const node& a,const node& b){return a.d > b.d;} | ||
+ | priority_queue<node> q; | ||
+ | void dijkstra(){ | ||
+ | for (int i = 1; i <= T; i++) d[i] = INF,vis[i] = false; | ||
+ | d[S] = 0; | ||
+ | node u; | ||
+ | q.push((node){S,d[S]}); | ||
+ | while (!q.empty()){ | ||
+ | u = q.top(); q.pop(); | ||
+ | if (vis[u.u]) continue; | ||
+ | vis[u.u] = true; | ||
+ | Redge(u.u) if (!vis[to = ed[k].to] && d[to] > d[u.u] + ed[k].w){ | ||
+ | d[to] = d[u.u] + ed[k].w; | ||
+ | q.push((node){to,d[to]}); | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | int main(){ | ||
+ | n = read(); m = read(); | ||
+ | int l,r,w; char c; | ||
+ | for (int i = 1; i <= m; i++){ | ||
+ | l = read(); r = read(); scanf("%c",&c); w = read(); | ||
+ | if (c == 'L') R[l][r] = w; | ||
+ | else C[l][r] = w; | ||
+ | } | ||
+ | for (int i = 1; i <= n - 1; i++) | ||
+ | for (int j = 1; j <= i; j++){ | ||
+ | //puts("LXT"); | ||
+ | //printf("[%d,%d] [%d,%d]\n",i + 1,j + 1,i + 1,j); | ||
+ | //cout << C[i + 1][j + 1] << ' ' << R[i + 1][j] << endl; | ||
+ | if (j < i && C[j + 1][i + 1]) build(id(i,j),id(i,j + 1),C[j + 1][i + 1]); | ||
+ | if (i < n - 1 && R[j][i + 1]) build(id(i,j),id(i + 1,j),R[j][i + 1]); | ||
+ | } | ||
+ | S = 0; T = n * (n - 1) / 2 + 1; | ||
+ | for (int i = 1; i <= n - 1; i++) if (C[1][i + 1]) build(S,id(i,1),C[1][i + 1]); | ||
+ | for (int i = 1; i <= n - 1; i++) if (R[i][n]) build(id(n - 1,i),T,R[i][n]); | ||
+ | dijkstra(); | ||
+ | if (d[T] != INF) printf("%lld\n",d[T]); | ||
+ | else puts("-1"); | ||
+ | return 0; | ||
+ | } | ||
+ | </code> | ||
+ | </hidden> | ||
+ | |||
===== 训练实况 ===== | ===== 训练实况 ===== | ||
- | 开场 发现**D**很简单 12:08 hxm 过**D** wxg想出**B**题做法 fyh开写**B** 12:08~12:50 fyh狂wa**B** wxg hxm想出**C** hxm开写**C** 13:33 hxm过C 在想**B**的错误和**F**,尝试用分数处理精度问题 改为wxg写**B** 13:33~14:30 **B**卡常 又wa又T hxm想出**F** 开写 15:04 hxm过**F** wxg继续尝试**B**,放弃 ,wxg开想**G** 15:04~16:00 ?? 16:00 看J题过得人多 fyh想**J** 16:36 fyh 过**J** wxg写**G**,未知原因段错误,结束。 | + | 开场 发现**D**很简单 |
+ | \\ 12:08 hxm 过**D** wxg想出**B**题做法 fyh开写**B** | ||
+ | \\ 12:08~12:50 fyh狂wa**B** wxg hxm想出**C** hxm开写**C** | ||
+ | \\ 13:33 hxm过C 在想**B**的错误和**F**,尝试用分数处理精度问题 改为wxg写**B** | ||
+ | \\ 13:33~14:30 **B**卡常 又wa又T hxm想出**F** 开写 | ||
+ | \\ 15:04 hxm过**F** wxg继续尝试**B**,放弃 ,wxg开想**G** | ||
+ | \\ 15:04~16:00 ?? | ||
+ | \\ 16:00 看J题过得人多 fyh想**J** | ||
+ | \\ 16:36 fyh 过**J** wxg写**G**,未知原因段错误,结束。 | ||
===== 训练总结 ===== | ===== 训练总结 ===== | ||
- | 因为很少人过,没有读**I** **K**题因为过的人少没有深想 **H**没有仔细想 **B**陷入无解,纠结太久 总结:计算几何最后再写 对榜的利用价值?? | + | 因为很少人过,没有读**I** |
+ | \\ **K**题因为过的人少没有深想 | ||
+ | \\ **H**没有仔细想 | ||
+ | \\ **B**陷入无解,纠结太久 | ||
+ | \\ 总结:计算几何最后再写 对榜的利用价值?? |