XVIII Open Cup named after E.V. Pankratiev. Eastern Grand Prix

Claris發表於2018-04-05

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

  

相關文章