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

  

XVIII Open Cup named after E.V. Pankratiev. Eastern Grand Prix的更多相关文章

  1. XVIII Open Cup named after E.V. Pankratiev. Ukrainian Grand Prix

    A. Accommodation Plan 对于已知的$K$个点,离它们距离都不超过$L$的点在树上是一个连通块,考虑在每种方案对应的离$1$最近的点统计. 即对于每个点$x$,统计离它距离不超过$L ...

  2. X Open Cup named after E.V. Pankratiev. European Grand Prix

    A. Arithmetic Rectangle 对于一行或者一列的情况可以递推求出最大值. 对于至少一行或者一列的情况,可以定义四个格子一组横向和纵向的相等关系,然后悬线法求最大子矩阵. 时间复杂度$ ...

  3. XVIII Open Cup named after E.V. Pankratiev. Grand Prix of SPb

    A. Base $i - 1$ Notation 两个性质: $2=1100$ $122=0$ 利用这两条性质实现高精度加法即可. 时间复杂度$O(n)$. #include<stdio.h&g ...

  4. XVIII Open Cup named after E.V. Pankratiev. Grand Prix of Siberia

    1. GUI 按题意判断即可. #include<stdio.h> #include<iostream> #include<string.h> #include&l ...

  5. XVIII Open Cup named after E.V. Pankratiev. Grand Prix of Peterhof

    A. City Wall 找规律. #include<stdio.h> #include<iostream> #include<string.h> #include ...

  6. XVIII Open Cup named after E.V. Pankratiev. GP of Urals

    A. Nutella’s Life 斜率优化DP显然,CDQ分治后按$a$排序建线段树,每层维护凸包,查询时不断将队首弹出即可. 时间复杂度$O(n\log^2n)$. #include<cst ...

  7. XVIII Open Cup named after E.V. Pankratiev. GP of Romania

    A. Balance 不难发现确定第一行第一列后即可确定全部,列不等式单纯形求解线性规划即可. #include<cstdio> #include<algorithm> usi ...

  8. XVIII Open Cup named after E.V. Pankratiev. Grand Prix of Khamovniki

    A. Ability Draft 记忆化搜索. #include<stdio.h> #include<iostream> #include<string.h> #i ...

  9. XVIII Open Cup named after E.V. Pankratiev. Grand Prix of Korea

    A. Donut 扫描线+线段树. #include<cstdio> #include<algorithm> using namespace std; typedef long ...

随机推荐

  1. mysql中常用的函数

    -- 基本上都是抄的别人整理的 -- 一.数学函数 ABS(x) -- 返回x的绝对值 BIN(x) -- 返回x的二进制(OCT返回八进制,HEX返回十六进制) CEILING(x) -- 返回大于 ...

  2. java BIO/NIO/AIO 学习

    一.了解Unix网络编程5种I/O模型 1.1.阻塞式I/O模型 阻塞I/O(blocking I/O)模型,进程调用recvfrom,其系统调用直到数据报到达且被拷贝到应用进程的缓冲区中或者发生错误 ...

  3. Entity Framework入门教程(3)---EF中的上下文简介

    1.DbContext(上下文类) 在DbFirst模式中,我们添加一个EDM(Entity Data Model)后会自动生成一个.edmx文件,这个文件中包含一个继承DbContext类的上下文实 ...

  4. Cygwin添加到鼠标右键

    From:http://www.cnblogs.com/killerlegend/p/3960112.html 在cygwin中安装chere 管理员权限执行mintty,输入下列命令即可. cher ...

  5. 第一节:框架前期准备篇之Log4Net日志详解

    一. Log4Net简介 Log4net是从Java中的Log4j迁移过来的一个.Net版的开源日志框架,它的功能很强大,可以将日志分为不同的等级,以不同的格式输出到不同的存储介质中,比如:数据库.t ...

  6. 18、cookies与session学习笔记

    本文记录学习 cookies 和 session 的一些小练习和知识点   知识点1    cookies 和 session 的由来   HTTP协议是无状态的协议,因为一旦浏览器和服务器之间的请求 ...

  7. [物理学与PDEs]第5章习题3 第二 Piola 应力张量的对称性

    试证明: 在物质描述下, 动量矩守恒定律等价于第二 Piola 应力张量的对称性. 证明: 由 $$\beex \bea \int_{G_t}\rho\sex{{\bf y}\times\cfrac{ ...

  8. 使用HBuilder+MUI+Flask后端服务器框架+Mongodb数据库开发手机APP

    1.开发准备HBuilder: 1.下载安装HBuilder2.创建APP项目 3.代码示例: <!doctype html> <html lang="en"&g ...

  9. easyui系列一 下拉框之组合框combobox

    一.基础组合框 示例 <select class="easyui-combobox" name="state" style="width:200 ...

  10. JdbcTemplate中queryForObject方法返回空结果或不正确结果数量的解决方法

    在使用Spirng提供的JdbcTemplate中名为queryForObject API进行数据库查询时有时会抛出如下异常: org.springframework.dao.EmptyResultD ...