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;
}
XVIII Open Cup named after E.V. Pankratiev. Eastern Grand Prix的更多相关文章
- XVIII Open Cup named after E.V. Pankratiev. Ukrainian Grand Prix
A. Accommodation Plan 对于已知的$K$个点,离它们距离都不超过$L$的点在树上是一个连通块,考虑在每种方案对应的离$1$最近的点统计. 即对于每个点$x$,统计离它距离不超过$L ...
- X Open Cup named after E.V. Pankratiev. European Grand Prix
A. Arithmetic Rectangle 对于一行或者一列的情况可以递推求出最大值. 对于至少一行或者一列的情况,可以定义四个格子一组横向和纵向的相等关系,然后悬线法求最大子矩阵. 时间复杂度$ ...
- 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 ...
- XVIII Open Cup named after E.V. Pankratiev. Grand Prix of Siberia
1. GUI 按题意判断即可. #include<stdio.h> #include<iostream> #include<string.h> #include&l ...
- XVIII Open Cup named after E.V. Pankratiev. Grand Prix of Peterhof
A. City Wall 找规律. #include<stdio.h> #include<iostream> #include<string.h> #include ...
- XVIII Open Cup named after E.V. Pankratiev. GP of Urals
A. Nutella’s Life 斜率优化DP显然,CDQ分治后按$a$排序建线段树,每层维护凸包,查询时不断将队首弹出即可. 时间复杂度$O(n\log^2n)$. #include<cst ...
- XVIII Open Cup named after E.V. Pankratiev. GP of Romania
A. Balance 不难发现确定第一行第一列后即可确定全部,列不等式单纯形求解线性规划即可. #include<cstdio> #include<algorithm> usi ...
- XVIII Open Cup named after E.V. Pankratiev. Grand Prix of Khamovniki
A. Ability Draft 记忆化搜索. #include<stdio.h> #include<iostream> #include<string.h> #i ...
- XVIII Open Cup named after E.V. Pankratiev. Grand Prix of Korea
A. Donut 扫描线+线段树. #include<cstdio> #include<algorithm> using namespace std; typedef long ...
随机推荐
- 应用调试(五)侵入式SWI
目录 应用调试(五)侵入式SWI 场景应用 测试程序 修改APP的bin 修改SWI 获得当前进程的寄存器 测试运行 恢复代码 进程间内存拷贝 TODO 更多参考文献 title: 应用调试(五)侵入 ...
- 第六节: EF高级属性(二) 之延迟加载、立即加载、显示加载(含导航属性)
一. 简介 上一个章节中,也介绍了立即加载和延迟加载,但上一个章节是针对单表而言的,不含外键,立即也好,延迟也好,都是指单表中的数据.但本章节重点介绍的三种加载方式均是针对含(导航属性.外键)的情况下 ...
- UML建工工具
本篇博文简单介绍一下自己在搜索UML建模工具的过程中收集到的一些信息. 如果想用中文的,可以考虑楚凡科技的Trufun Plato,不过最近好像没有怎么更新了. 很多前辈以前用的是Rational R ...
- JAVA传递带有空格的参数
String s="b2 + b1"; Process child = Runtime.getRuntime().exec("C:\\eclipse-workspace\ ...
- [物理学与PDEs]第1章第6节 电磁场的标势与矢势 6.1 预备知识
1. 若 ${\bf B}$ 为横场 ($\Div{\bf B}=0\ra {\bf k}\cdot {\bf B}=0\ra $ 波的振动方向与传播方向平行), 则 $$\bex \exists\ ...
- 如何使用AB PLC仿真软件Studio 5000 Logix Emulate
前言:在学习PLC编程或程序开发过程中,如果身边没有实体PLC,又想验证程序逻辑,这时,仿真软件是不错的选择.针对AB PLC的仿真软件Studio 5000 Logix Emulate,有的同学说: ...
- C#处理非托管资源
using System; //处理非托管资源 //例如:文件句柄.网络连接.数据库连接 //实现IDisposable不意味着也应该实现一个终结器,终结器会带来额外开销 //发布本机资源,要释放本机 ...
- 电子医疗设备创新研发应该用i.MX6Q开发板吗?为医疗设备提供解决方案
伴随医疗信息化.移动化.智能化的不断发展,居民对自身健康的关注度持续加强,全球医疗电子产业近年来持续保持快速增长态势.同时,源于庞大的人口基数以及迅速增长的老龄化人口带来持续增长的医疗服务需求,加之全 ...
- Synchronized 和 Volatile
Synchronized : 称为重量级锁,经过优化后,也没那么重了 一.CAS 1.CAS:Compare and Swap, 翻译成比较并交换. 2.java.util.concurrent包中借 ...
- Visual Studio Code(VSCODE)语言设置
Visual Studio Code(VSCODE)语言设置 语言设置 1.快捷键 Windows.Linux 快捷键是:ctrl+shift+p macOS 快捷键是:command + shift ...