XVIII Open Cup named after E.V. Pankratiev. Eastern Grand Prix
A. Artifacts
建立语法分析树,首先根据上下界判断是否有解,然后将所有数按下界填充,线段树判断是否存在和超过$K$的子区间。
B. Brackets and Dots
最优解中一定包含一对中间都是点的$()$,set维护所有这种pair即可。
#include<cstdio> #include<set> #include<cstring> #include<algorithm> using namespace std; typedef pair<int,int>P; const int N=500010; int n,i,m,x,y; set<int>A; set<P>B; char a[N]; inline bool gao(int x,int y){ set<P>::iterator it=B.lower_bound(P(x,-1)); if(it==B.end())return 0; if(it->second>y)return 0; int l=it->first,r=it->second; B.erase(it); set<int>::iterator i=A.find(l),j=A.find(r); int pre=0,nxt=0; if(i!=A.begin()){ i--; if(a[*i]=='(')pre=*i; } j++; if(j!=A.end()){ if(a[*j]==')')nxt=*j; } A.erase(l); A.erase(r); if(pre&&nxt)B.insert(P(pre,nxt)); return 1; } int main(){ scanf("%s",a+1); n=strlen(a+1); for(i=1;i<=n;i++){ A.insert(i); if(a[i]=='('&&a[i+1]==')')B.insert(P(i,i+1)); } scanf("%d",&m); while(m--){ scanf("%d%d",&x,&y); int ans=0; while(gao(x,y))ans++; printf("%d\n",ans*2); } }
C. Crossword
首先$O(n^2)$预处理出竖着的两条对于每种间隔的贡献,然后$O(n^2)$枚举横着的摆法,再根据预处理的数组求出每个位置竖着的放法,前缀和优化即可。
时间复杂度$O(n^3)$。
#include<cstdio> #include<cstring> #include<string> #include<algorithm> #include<iostream> #include<cstdlib> using namespace std; string a[9]; int q[9],i; long long ans; int f[555],g[555]; int wc[160][29][29],wd[160][29][29]; inline int cal(const string&A,int d,char x,char y){ int ret=0; for(int i=d;i<A.size();i++)if(A[i-d]==x&&A[i]==y)ret++; return ret; } void pre(const string&A,int w[][29][29]){ for(int i=0;i<160;i++)for(int j=0;j<29;j++)for(int k=0;k<29;k++)w[i][j][k]=0; for(int i=0;i<A.size();i++)for(int j=i+1;j<A.size();j++){ w[j-i][A[i]][A[j]]++; } } void solve(const string&A,const string&B,const string&C,const string&D){ int i,j,k,x,y,z,o,dx,dy; int lena=A.size(),lenb=B.size(),lenc=C.size(),lend=D.size(); pre(C,wc); pre(D,wd); for(dy=-150;dy<=150;dy++){ int L=max(0,dy),R=min(lena-1,dy+lenb-1); if(R-L+1<3)continue; for(dx=2;dx<=150;dx++){ f[L-1]=0; for(i=L;i<=R;i++){ /*f[i]=cal(C,dx,A[i],B[i-dy]); g[i]=cal(D,dx,A[i],B[i-dy]); if(f[i]!=wc[dx][A[i]][B[i-dy]]){ printf("%d %d %d\n",dx,A[i],B[i-dy]); for(int t=0;t<C.size();t++)printf("%d ",C[t]); puts(""); printf("%d %d\n",f[i],wc[dx][A[i]][B[i-dy]]); while(1); }*/ f[i]=wc[dx][A[i]][B[i-dy]],g[i]=wd[dx][A[i]][B[i-dy]]; } for(i=L;i<=R;i++)f[i]+=f[i-1]; for(i=L+2;i<=R;i++)ans+=f[i-2]*g[i]; } } } int main(){ for(i=1;i<=4;i++){ cin>>a[i]; for(int j=0;j<a[i].size();j++)a[i][j]-='a'-1; q[i]=i; } do{ solve(a[q[1]],a[q[2]],a[q[3]],a[q[4]]); }while(next_permutation(q+1,q+5)); printf("%lld",ans); }
D. Digit
从高位到低位贪心。
#include<stdio.h> #include<iostream> #include<string.h> #include<string> #include<ctype.h> #include<math.h> #include<set> #include<map> #include<vector> #include<queue> #include<bitset> #include<algorithm> #include<time.h> using namespace std; void fre() { } #define MS(x, y) memset(x, y, sizeof(x)) #define ls o<<1 #define rs o<<1|1 typedef long long LL; typedef unsigned long long UL; typedef unsigned int UI; template <class T1, class T2>inline void gmax(T1 &a, T2 b) { if (b > a)a = b; } template <class T1, class T2>inline void gmin(T1 &a, T2 b) { if (b < a)a = b; } const int N = 1e5 + 10, M = 0, Z = 1e9 + 7, inf = 0x3f3f3f3f; template <class T1, class T2>inline void gadd(T1 &a, T2 b) { a = (a + b) % Z; } int casenum, casei; int n, l; int cnt[10]; vector<int>vt[10]; int w[10]; bool ok[N]; int ans[N]; char s[N]; int solve() { MS(ok, 0); MS(w, 0); int p = n + 1; while(p > 1 && s[p - 1] == '9')--p; ok[p - 1] = 1; bool can = ok[0]; for(int i = 1; i <= n; ++i) { can |= ok[i]; if(can) { for(int j = 1; j <= s[i] - '0'; ++j)w[j]++; } else { int top = s[i] - '0' - 1; if(top == 0 && s[i] == '1')top = 1; for(int j = 1; j <= top; ++j)w[j]++; } } int v = -1; int g = -1; for(int i = 9; i >= 0; --i) { if(w[i] > g) { g = w[i]; v = i; } } return v; } void table() { for(n = 1; n <= 9999; ++n) { int x = n; while(x) { ++cnt[x % 10]; x /= 10; } int v = -1; int g = -1; for(int i = 9; i >= 0; --i) { if(cnt[i] > g) { g = cnt[i]; v = i; } } ans[n] = v; //vt[v].push_back(n); } for(int i = 1; i <= 9; ++i) { printf("# %d: ", i); for(auto x : vt[i])printf("%d ", x); puts(""); } } int main() { //table(); while(~scanf("%s",s + 1)) //for(int x = 1; x <= 9999; ++x) { //sprintf(s + 1, "%d", x); n = strlen(s + 1); int ans1 = solve(); //printf("%d:\n", x); printf("%d\n", ans1); /* int ans2 = ans[x]; printf("%d\n", ans2); if(ans1 != ans2) while(1); */ //int x; sscanf(s + 1, "%d", &x); //printf("%d\n", ans[x]); } return 0; } /* 【trick&&吐槽】 【题意】 【分析】 【时间复杂度&&优化】 */
E. Enormous Table
找规律。
#include<cstdio> #include<cstring> #include<queue> #include<algorithm> using namespace std; const int N= 1e6 + 10; typedef long long LL; LL a, b; int main(){ while(~ scanf("%lld%lld", &a, &b)){ LL x = a + b - 2; LL y = (1 + x) * x / 2; LL ans; if((a + b) & 1) ans = y + a; else ans = y + b; printf("%lld\n", ans); } } /* 4 7 1 4 1 2 1 2 1 4 2 3 2 3 3 4 3 4 4 3 1 2 1 2 2 4 4 3 5 8 3 1 3 2 5 2 3 4 4 5 4 1 2 1 3 5 3 1 */
F. Funny Language
首先可以$O(n\log n)$枚举出所有位于同一段序列内部的区间$\gcd$,只需要考虑横跨了多个序列的情况。
考虑容斥,设$f_d$表示$d|\gcd$的方案数,则实际值$g_d=f_d-g_{2d}-g_{3d}-...$,可以在$O(n\log n)$的时间内求出所有$g$。
考虑如何求$f_d$:对于每个序列计算有多少个前后缀是$d$的倍数,以及整个序列是否是$d$的倍数,枚举横跨序列的个数用组合数计算答案即可。
时间复杂度$O(nd(n))$。
#include<cstdio> #include<vector> using namespace std; const int N=80010,P=1000000007; int D,i,j,fac[N],inv[N],ans[N],fin; int n,len[N],st[N],en[N],pool[N],cur,base; int vis[N],vl[N],vr[N],ok[N],all,m,q[N]; int sl[2],sr[2],slr[2]; vector<int>vpre[N],vsuf[N],vall[N]; int gcd(int a,int b){return b?gcd(b,a%b):a;} inline int C(int n,int m){return n<m?0:1LL*fac[n]*inv[m]%P*inv[n-m]%P;} inline void up(int&a,int b){a=a+b<P?a+b:a+b-P;} inline void solve(int L,int R){ static int a[N],l[N],v[N]; int n=R-L+1,i,j; for(i=1;i<=n;i++)a[i]=pool[L+i-1]; for(i=0;i<=n;i++)l[i]=v[i]=0; for(i=1;i<=n;i++)for(v[i]=a[i],j=l[i]=i;j;j=l[j]-1){ v[j]=gcd(v[j],a[i]); while(l[j]>1&&gcd(a[i],v[l[j]-1])==gcd(a[i],v[j]))l[j]=l[l[j]-1]; up(ans[v[j]],1LL*(j-l[j]+1)*base%P); } } inline void visit(int x){ if(vis[x]==D)return; vis[x]=D; vl[x]=vr[x]=ok[x]=0; q[++m]=x; } inline int work(){ int i,j,k,x,y,ret,ans=0; all=m=0; for(i=D;i<N;i+=D){ for(j=0;j<vall[i].size();j++){ x=vall[i][j]; visit(x); ok[x]=1; all++; } for(j=0;j<vpre[i].size();j++){ x=vpre[i][j]; visit(x); vl[x]++; } for(j=0;j<vsuf[i].size();j++){ x=vsuf[i][j]; visit(x); vr[x]++; } } for(i=0;i<2;i++)sl[i]=sr[i]=slr[i]=0; for(i=1;i<=m;i++){ x=q[i]; up(sl[ok[x]],vl[x]); up(sr[ok[x]],vr[x]); up(slr[ok[x]],1LL*vl[x]*vr[x]%P); //printf("x=%d vl=%d vr=%d ok=%d\n",x,vl[x],vr[x],ok[x]); } //printf("all=%d\n",all); for(x=0;x<2;x++)for(y=0;y<2;y++){ ret=all-x-y; if(ret<0)continue; for(k=0;k<=ret;k++){ if(n-k-2<0)continue; int now=1LL*C(ret,k)*fac[k]%P*(n-k-1)%P*fac[n-k-2]%P; int tmp=1LL*sl[x]*sr[y]%P; if(x==y)tmp=(tmp-slr[x]+P)%P; //printf("x=%d y=%d ret=%d k=%d now=%d tmp=%d\n",x,y,ret,k,now,tmp); ans=(1LL*now*tmp+ans)%P; } } //if(ans)printf("ans[%d]=%d\n",D,ans); return ans; } int main(){ for(fac[0]=i=1;i<N;i++)fac[i]=1LL*fac[i-1]*i%P; for(inv[0]=inv[1]=1,i=2;i<N;i++)inv[i]=1LL*(P-inv[P%i])*(P/i)%P; for(i=2;i<N;i++)inv[i]=1LL*inv[i-1]*inv[i]%P; scanf("%d",&n); base=1LL*fac[n-1]*n%P; for(i=1;i<=n;i++){ scanf("%d",&len[i]); st[i]=cur+1; en[i]=cur+len[i]; for(j=st[i];j<=en[i];j++)scanf("%d",&pool[j]); cur+=len[i]; int pre=pool[st[i]],suf=pool[en[i]]; for(j=st[i];j<=en[i];j++){ pre=gcd(pre,pool[j]); vpre[pre].push_back(i); } vall[pre].push_back(i); for(j=en[i];j>=st[i];j--){ suf=gcd(suf,pool[j]); vsuf[suf].push_back(i); } } for(D=1;D<N;D++)ans[D]=work(); for(i=N-1;i;i--)for(j=i+i;j<N;j+=i)ans[i]=(ans[i]-ans[j]+P)%P; for(i=1;i<=n;i++)solve(st[i],en[i]); for(i=1;i<N;i++)fin=(1LL*i*ans[i]+fin)%P; printf("%d",fin); }
G. Game of Tic-Tac-Toe
总状态只有$2\times 3^9$,博弈DP后即可得到下棋策略。
#include<stdio.h> #include<iostream> #include<string.h> #include<string> #include<ctype.h> #include<math.h> #include<set> #include<map> #include<vector> #include<queue> #include<bitset> #include<algorithm> #include<time.h> using namespace std; void fre() { } #define MS(x, y) memset(x, y, sizeof(x)) #define ls o<<1 #define rs o<<1|1 typedef long long LL; typedef unsigned long long UL; typedef unsigned int UI; template <class T1, class T2>inline void gmax(T1 &a, T2 b) { if (b > a)a = b; } template <class T1, class T2>inline void gmin(T1 &a, T2 b) { if (b < a)a = b; } const int N = 1010, M = 0, Z = 1e9 + 7, inf = 0x3f3f3f3f; template <class T1, class T2>inline void gadd(T1 &a, T2 b) { a = (a + b) % Z; } int casenum, casei; int n; int f[3*3*3*3*3*3*3*3*3][2]; int a[3][3]; int check() { int j = 0; for(int i = 0; i < 3; ++i) { if(a[i][j] == 0 && a[i][j + 1] == 0 && a[i][j + 2] == 0)return 0; if(a[j][i] == 0 && a[j + 1][i] == 0 && a[j + 2][i] == 0)return 0; if(a[i][j] == 1 && a[i][j + 1] == 1 && a[i][j + 2] == 1)return 1; if(a[j][i] == 1 && a[j + 1][i] == 1 && a[j + 2][i] == 1)return 1; } if(a[0][0] == 0 && a[1][1] == 0 && a[2][2] == 0)return 0; if(a[0][2] == 0 && a[1][1] == 0 && a[2][0] == 0)return 0; if(a[0][0] == 1 && a[1][1] == 1 && a[2][2] == 1)return 1; if(a[0][2] == 1 && a[1][1] == 1 && a[2][0] == 1)return 1; return 2; } int v[10]; void getA(int x) { for(int j = 0; j < 9; ++j) { a[j / 3][j % 3] = x % 3; if(a[j / 3][j % 3]) -- a[j / 3][j % 3]; else a[j / 3][j % 3] = 2; x /= 3; } } int main() { int top = 3*3*3*3*3*3*3*3*3; v[0] = 1; for(int i = 1; i <= 9; ++i)v[i] = v[i - 1] * 3; for(int i = top - 1; i >= 0; --i) { getA(i); int win = check(); if(win < 2) { //printf("win status %d: %d\n", i, win); f[i][0] = f[i][1] = win; continue; } bool end = 1; for(int j = 0; j < 9; ++j) { if(a[j / 3][j % 3] == 2) { end = 0; } } if(end) { f[i][0] = f[i][1] = 2; continue; } for(int k = 0; k < 2; ++k)//who play { bool can_draw = 0; f[i][k] = -1; for(int j = 0; j < 9; ++j) { if(a[j / 3][j % 3] == 2) { int nxt = i + v[j] * (k + 1); if(f[nxt][1 ^ k] == k) { f[i][k] = k; } else if(f[nxt][1 ^ k] == 2) { can_draw = 1; } } } if(f[i][k] == -1) { f[i][k] = can_draw ? 2 : (1 ^ k); } } } //printf("%d\n", f[0][0]); char C; scanf(" %c", &C); { int me = 1, ene = 0; int step = 0; int now = 0; if(C == 'O') { int y, x; scanf("%d%d", &y, &x); --y; --x; now += v[y * 3 + x] * 1; ++step; } getA(now); //printf("sta: %d, %d\n", now, f[now][me]); while(step < 9) { int y = -1; int x = -1; for(int i = 0; i < 3; ++i) { for(int j = 0; j < 3; ++j)if(a[i][j] == 2) { int nxt = now + v[i * 3 + j] * 2; //printf("ene: %d %d\n", nxt, f[nxt][ene]); if(f[nxt][ene] != ene) { y = i; x = j; } } } printf("%d %d\n", y + 1, x + 1); fflush(stdout); now += v[y * 3 + x] * 2; ++step; getA(now); char s[100]; scanf("%s", s); if(isalpha(s[0]))return 0; sscanf(s, "%d", &y); scanf("%s", s); sscanf(s, "%d", &x); --y; --x; now += v[y * 3 + x] * 1; ++step; getA(now); } } return 0; } /* 【trick&&吐槽】 【题意】 【分析】 【时间复杂度&&优化】 */
H. Hill and Subhill
高维差分。
#include<cstdio> #include<cstring> #define FOR(i,a,b) for(int i=a;i<=b;i++) #define FOV(i,a,b) for(int i=a;i>=b;i--) #define CLR(a) memset(a,0,sizeof a) #define U 105][105][105 #define FFF FOR(i,1,N)FOR(j,1,i)FOR(k,1,j) #define VVV FOV(i,N,1)FOV(j,i,1)FOV(k,j,1) typedef long long LL; int N,M,Q,x,y,z,a,d3as[U],d3ae[U],d3ds[U],d3de[U]; LL d2a[U],d2d[U],d1[U],suffix1d[U],suffix2d[U],s1[U],s2[U],s31[U],s32[U]; inline void read(int&a){char c;while(!(((c=getchar())>='0')&&(c<='9')));a=c-'0';while(((c=getchar())>='0')&&(c<='9'))(a*=10)+=c-'0';} void solve(){ int x,y,z,a; CLR(d3as); CLR(d3ae); CLR(d3ds); CLR(d3de); CLR(d2a); CLR(d2d); CLR(d1); CLR(suffix1d); CLR(suffix2d); CLR(s1); CLR(s2); CLR(s31); CLR(s32); for(int i=0;i<M;i++){ read(x),read(y),read(z),read(a); d3as[x][y][z]++; d3as[x+a][y+a][z+a]--; d3ae[x+a][y+a][z]--; d3ae[x+a][y+a][z+a]++; d3ds[x+a][y][z]--; d3ds[x+a][y+a][z+a]++; d3de[x+a][y+a][z]++; d3de[x+a][y+a][z+a]--; } FFF{ d2a[i][j][k]+=d3as[i][j][k]; d2a[i][j][k]+=d3ae[i][j][k]; d2d[i][j][k]+=d3ds[i][j][k]; d2d[i][j][k]+=d3de[i][j][k]; d3as[i+1][j+1][k+1]+=d3as[i][j][k]; d3ae[i][j][k+1]+=d3ae[i][j][k]; d3ds[i][j+1][k+1]+=d3ds[i][j][k]; d3de[i][j][k+1]+=d3de[i][j][k]; } FFF{ d1[i][j][k]+=d2a[i][j][k]; d1[i][j][k]+=d2d[i][j][k]; d2a[i+1][j+1][k]+=d2a[i][j][k]; d2d[i][j+1][k]+=d2d[i][j][k]; } FFF{ suffix1d[i][j][k]+=d1[i][j][k]; d1[i+1][j][k]+=d1[i][j][k]; } VVV suffix1d[i][j][k]+=suffix1d[i+1][j][k]; VVV suffix2d[i][j][k]+=suffix1d[i][j][k]+suffix2d[i+1][j+1][k]; VVV s1[i][j][k]+=suffix2d[i][j][k]+s1[i+1][j+1][k+1]; VVV s2[i][j][k]+=suffix2d[i][j][k]+s2[i][j][k+1]; VVV s31[i][j][k]+=suffix1d[i][j][k]+s31[i][j+1][k]; VVV s32[i][j][k]+=s31[i][j][k]+s32[i][j+1][k+1]; VVV s31[i][j][k]+=s31[i][j][k+1]; while(Q--){ read(x),read(y),read(z),read(a); LL ans=s1[x][y][z]-s1[x+a][y+a][z+a]; ans-=s2[x+a][y+a][z]-s2[x+a][y+a][z+a]; ans+=s31[x+a][y+a][z]-s31[x+a][y+a][z+a]; ans-=s32[x+a][y][z]-s32[x+a][y+a][z+a]; printf("%lld\n",ans); } } int main(){ while(~scanf("%d%d%d",&N,&M,&Q))solve(); return 0; }
I. It is panic?
按题意模拟。
#include<stdio.h> #include<iostream> #include<string.h> #include<string> #include<ctype.h> #include<math.h> #include<set> #include<map> #include<vector> #include<queue> #include<bitset> #include<algorithm> #include<time.h> using namespace std; void fre() { } #define MS(x, y) memset(x, y, sizeof(x)) #define ls o<<1 #define rs o<<1|1 typedef long long LL; typedef unsigned long long UL; typedef unsigned int UI; template <class T1, class T2>inline void gmax(T1 &a, T2 b) { if (b > a)a = b; } template <class T1, class T2>inline void gmin(T1 &a, T2 b) { if (b < a)a = b; } const int N = 1010, M = 0, Z = 1e9 + 7, inf = 0x3f3f3f3f; template <class T1, class T2>inline void gadd(T1 &a, T2 b) { a = (a + b) % Z; } int casenum, casei; int n; char s[N]; int main() { while(~scanf("%s",s)) { int n = strlen(s); int l = -1; while(l < n - 1 && s[l + 1] == 'A')++l; int r = n; while(r > 0 && s[r - 1] == '!')--r; if(l >= 0 && r < n && r == l + 1)puts("Panic!"); else puts("No panic"); } return 0; } /* 【trick&&吐槽】 【题意】 【分析】 【时间复杂度&&优化】 */
J. JokeCoin
按左端点排序,树状数组维护右端点即可优化DP至$O(n\log n)$。
#include<cstdio> #include<vector> #include<algorithm> using namespace std; typedef vector<int>V; typedef long long ll; const int N=200010,M=25,P=1000000007; int n, m; struct A { int st, ed, v; }a[N]; inline bool cmp(const A&a,const A&b){ return a.st<b.st; } ll ans,f[N]; void ins(int x,ll p){for(;x<N;x+=x&-x)f[x]=max(f[x],p);} ll ask(int x){ll t=0;for(;x;x-=x&-x)t=max(t,f[x]);return t;} int main(){ scanf("%d%d",&n,&m); for(int i = 1; i <= n; i ++){ int x, y, z, xx, yy, zz, v; scanf("%d:%d:%d%d:%d:%d%d", &x, &y, &z, &xx, &yy, &zz, &v); int t1 = x * 3600 + y * 60 + z; int t2 = xx * 3600 + yy * 60 + zz; v -= (t2 - t1) * m; a[i].st = t1; a[i].ed = t2; a[i].v = v; } for(int i=1;i<=n;i++)a[i].st+=5,a[i].ed+=5; sort(a+1,a+n+1,cmp); for(int i=1;i<=n;i++){ ll dp=ask(a[i].st)+a[i].v; ans=max(ans,dp); ins(a[i].ed,dp); } printf("%lld",ans); /*for(int i = 1; i <= n; i ++){ printf("%d %d %d\n", a[i].st, a[i].ed, a[i].v); }*/ } /* 4 0 03:00:00 10:10:00 20 01:00:00 02:30:00 50 16:10:00 19:00:00 100 02:30:00 22:00:00 200 3 1 16:59:00 17:00:00 100 01:01:01 01:01:11 20 12:00:00 13:00:00 3601 4 10 00:00:05 00:01:55 1100 00:00:10 00:00:21 100 00:01:50 00:02:00 80 23:59:00 23:59:05 40 */
K. King and ICPC
分治,预处理出$mid$到$[l,r]$每个点的背包,然后利用这个信息处理所有经过$mid$的询问。
时间复杂度$O((nd+m)\log n+md)$。
#include<cstdio> #include<vector> using namespace std; typedef vector<int>V; typedef long long ll; const int N=50010,M=55; const ll inf=1LL<<60; int n,m,q,i,j,a[N][3]; ll f[N][M],g[N][M]; int e[300010][2]; ll ans[300010]; inline void up(ll&a,ll b){a<b?(a=b):0;} void solve(int l,int r,V v){ if(l>r||!v.size())return; int mid=(l+r)>>1; int i,j,k; //[l..mid] [mid+1..r] for(i=l;i<=mid+1;i++)for(j=0;j<m;j++)f[i][j]=-inf; f[mid+1][0]=0; for(i=mid;i>=l;i--)for(j=0;j<m;j++)for(k=0;k<3;k++)up(f[i][(j+a[i][k])%m],f[i+1][j]+a[i][k]); for(i=mid;i<=r;i++)for(j=0;j<m;j++)g[i][j]=-inf; g[mid][0]=0; for(i=mid+1;i<=r;i++)for(j=0;j<m;j++)for(k=0;k<3;k++)up(g[i][(j+a[i][k])%m],g[i-1][j]+a[i][k]); V vl,vr; for(i=0;i<v.size();i++){ int x=v[i]; if(e[x][1]<mid)vl.push_back(x); else if(e[x][0]>mid)vr.push_back(x); else{ for(j=0;j<m;j++)up(ans[x],f[e[x][0]][j]+g[e[x][1]][(m-j)%m]); } } solve(l,mid-1,vl); solve(mid+1,r,vr); } int main(){ scanf("%d%d",&n,&m); for(i=1;i<=n;i++)for(j=0;j<3;j++)scanf("%d",&a[i][j]); scanf("%d",&q); V v; for(i=1;i<=q;i++){ scanf("%d%d",&e[i][0],&e[i][1]); ans[i]=-inf; v.push_back(i); } solve(1,n,v); for(i=1;i<=q;i++){ if(ans[i]<0)ans[i]=-1; printf("%lld\n",ans[i]); } }
L. Longest Simple Paths
Dijkstra求出最短路树后点分治统计即可。
#include<cstdio> #include<algorithm> const int N=30010,M=120010,inf=~0U>>1; int n,m,k,i,x,y,z,g[N],v[M],w[M],nxt[M],ok[M],ed,d[N],vis[N],son[N],f[N],size,now,T,pos[N]; struct E{int x,y,w;E(){}E(int _x,int _y,int _z){x=_x,y=_y,w=_z;}}a[M]; inline bool cmp(E a,E b){return a.x==b.x?a.y>b.y:a.x<b.x;} inline void read(int&a){char c;while(!(((c=getchar())>='0')&&(c<='9')));a=c-'0';while(((c=getchar())>='0')&&(c<='9'))(a*=10)+=c-'0';} inline void add(int x,int y,int z){v[++ed]=y;w[ed]=z;nxt[ed]=g[x];ok[ed]=1;g[x]=ed;} struct Num{ int x,y; Num(){x=y=0;} Num(int _x,int _y){x=_x,y=_y;} inline Num operator+(Num b){ if(x==b.x)return Num(x,y+b.y); return x<b.x?b:Num(x,y); } inline void operator+=(Num b){*this=*this+b;} }tmp[N],ans; inline void up(int x,Num y){ if(pos[x]<T)pos[x]=T,tmp[x]=Num(); tmp[x]+=y; } inline Num get(int x){ if(pos[x]<T)return Num(); return tmp[x]; } struct PI{ int x,y; PI(){} PI(int _x,int _y){x=_x,y=_y;} inline PI operator+(PI b){return x<=b.x?PI(x,y):b;} }val[65537]; void build(int x,int a,int b){ val[x]=PI(inf,a); if(a==b)return; int mid=(a+b)>>1; build(x<<1,a,mid),build(x<<1|1,mid+1,b); } inline void change(int x,int a,int b,int c,int d){ if(a==b){val[x].x=d;return;} int mid=(a+b)>>1; c<=mid?change(x<<1,a,mid,c,d):change(x<<1|1,mid+1,b,c,d); val[x]=val[x<<1]+val[x<<1|1]; } void dfs(int x){ vis[x]=1; for(int i=g[x];i;i=nxt[i])if(!vis[v[i]]&&d[x]+w[i]==d[v[i]])a[++m]=E(x,v[i],w[i]),dfs(v[i]); } void findroot(int x,int pre){ son[x]=1;f[x]=0; for(int i=g[x];i;i=nxt[i])if(ok[i]&&v[i]!=pre){ findroot(v[i],x); son[x]+=son[v[i]]; if(son[v[i]]>f[x])f[x]=son[v[i]]; } if(size-son[x]>f[x])f[x]=size-son[x]; if(f[x]<f[now])now=x; } void dfscal(int x,int pre,int dep,int sum){ if(dep>=k)return; Num t=get(k-dep); if(t.y)ans+=Num(t.x+sum,t.y); for(int i=g[x];i;i=nxt[i])if(ok[i]&&v[i]!=pre)dfscal(v[i],x,dep+1,sum+w[i]); } void dfsadd(int x,int pre,int dep,int sum){ if(dep>=k)return; up(dep,Num(sum,1)); for(int i=g[x];i;i=nxt[i])if(ok[i]&&v[i]!=pre)dfsadd(v[i],x,dep+1,sum+w[i]); } void solve(int x){ int i; T++,up(1,Num(0,1)); for(i=g[x];i;i=nxt[i])if(ok[i])dfscal(v[i],x,2,w[i]),dfsadd(v[i],x,2,w[i]); for(i=g[x];i;i=nxt[i])if(ok[i])ok[i^1]=0,f[0]=size=son[v[i]],findroot(v[i],now=0),solve(now); } int main(){ read(n),read(m),read(k);k++; for(i=1;i<=m;i++){ read(x),read(y),read(z); a[i]=E(x,y,z); a[i+m]=E(y,x,z); } std::sort(a+1,a+m+m+1,cmp); for(i=1;i<=m+m;i++)add(a[i].x,a[i].y,a[i].w); for(i=2;i<=n;i++)d[i]=inf; build(1,1,n),change(1,1,n,1,0); while(val[1].x<inf)for(change(1,1,n,x=val[1].y,inf),i=g[x];i;i=nxt[i])if(d[x]+w[i]<d[v[i]])change(1,1,n,v[i],d[v[i]]=d[x]+w[i]); m=0,dfs(1); for(ed=i=1;i<=n;i++)g[i]=0; for(i=1;i<=m;i++)add(a[i].x,a[i].y,a[i].w),add(a[i].y,a[i].x,a[i].w); f[0]=size=n,findroot(1,now=0),solve(now); return printf("%d %d",ans.x,ans.y),0; }