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