[The Preliminary Contest for ICPC Asia Shanghai 2019]简要题解?

前言

大概是第一场AK的ACM比赛?
我太菜了,队友太强了.jpg
先把自己负责的题写一写,剩下的咕了
题目链接

Lightning Routing I

LCT模板题
对于每条偏爱路维护正着和反着两条直径,用两个set维护所有虚儿子的最长链
有板子就很舒服

Code

#include <set>
#include <cstdio>
#include <cstring>
#include <algorithm>
#define fo(i,a,b) for(int i=a;i<=b;i++)
#define fd(i,a,b) for(int i=a;i>=b;i--)
using namespace std;

typedef long long ll;

int read() {
	char ch;
	for(ch=getchar();ch<'0'||ch>'9';ch=getchar());
	int x=ch-'0';
	for(ch=getchar();ch>='0'&&ch<='9';ch=getchar()) x=x*10+ch-'0';
	return x;
}

void write(ll x) {
	if (!x) {puts("0");return;}
	char ch[20];int tot=0;
	for(;x;x/=10) ch[++tot]=x%10+'0';
	fd(i,tot,1) putchar(ch[i]);
	puts("");
}

const int N=2e5+5;
const ll inf=1e16;

struct Path{
	int u,v;ll w;
	Path(){}
	Path(int u,int v,ll w):
		u(u),v(v),w(w){}
	Path operator + (const ll x)const{return Path(u,v,w+x);}
	Path operator - (const ll x)const{return Path(u,v,w-x);}
	Path operator + (const Path& x)const{
		Path ret;
		ret.u=u;ret.v=x.u;
		if (ret.u<ret.v) swap(ret.u,ret.v);
		ret.w=w+x.w;
		return ret;
	}
	bool operator < (const Path& x)const{
		if (w!=x.w) return w<x.w;
		if (u!=x.u) return u<x.u;
		return v<x.v;
	}
};

struct Data{
	Path pre,suf,ans;ll sum;
	Data(){}
	Data(Path pre,Path suf,Path ans,ll sum):
		pre(pre),suf(suf),ans(ans),sum(sum){}
	Data operator + (const Data& x)const{
		Data ret;
		ret.pre=max(pre,x.pre+sum);
		ret.suf=max(suf+x.sum,x.suf);
		ret.ans=max(ans,x.ans);
		ret.ans=max(ret.ans,suf+x.pre);
		ret.sum=sum+x.sum;
		return ret;
	}
};

namespace LCT{
	int f[N],t[N][2],p[N],sta[N],top;
	multiset<Path> pre[N],ans[N];
	ll val[N];
	Data a[N],ra[N],dp[N];
	bool rev[N];

	void upd(int x) {
		int ls=t[x][0],rs=t[x][1];
		a[x]=ra[x]=Data(dp[x].pre+val[x],dp[x].pre+val[x],dp[x].ans,val[x]);
		if (ls) {
			a[x]=a[ls]+a[x];
			ra[x]=ra[x]+ra[ls];
		}
		if (rs) {
			a[x]=a[x]+a[rs];
			ra[x]=ra[rs]+ra[x];
		}
	}

	int son(int x) {return t[f[x]][1]==x;}

	void rotate(int x) {
		int y=f[x],z=son(x);
		if (f[y]) t[f[y]][son(y)]=x;
		else p[x]=p[y],p[y]=0;
		if (t[x][1-z]) f[t[x][1-z]]=y;
		t[y][z]=t[x][1-z];t[x][1-z]=y;
		f[x]=f[y];f[y]=x;
		upd(y);upd(x);
	}

	void reverse(int x) {
		if (!x) return;
		swap(t[x][0],t[x][1]);
		swap(a[x],ra[x]);
		rev[x]^=1;
	}

	void down(int x) {
		if (rev[x]) {
			reverse(t[x][0]);reverse(t[x][1]);
			rev[x]=0;
		}
	}

	void remove(int x,int y) {
		do {sta[++top]=x;x=f[x];} while (x!=y);
		for(;top;down(sta[top--]));
	}

	void splay(int x,int y) {
		remove(x,y);
		while (f[x]!=y) {
			if (f[f[x]]!=y) 
				if (son(x)==son(f[x])) rotate(f[x]);
				else rotate(x);
			rotate(x);
		}
	}

	void get(int x) {
		dp[x].pre=*pre[x].rbegin();
		dp[x].ans=*ans[x].rbegin();
		if (pre[x].size()>=2) {
			auto smx=pre[x].rbegin(),mx=smx;smx++;
			dp[x].ans=max(dp[x].ans,*smx+*mx+val[x]);
		}
	}

	void add(int x,int y) {
		pre[x].insert(a[y].pre);
		ans[x].insert(a[y].ans);
		get(x);
	}

	void del(int x,int y) {
		pre[x].erase(pre[x].find(a[y].pre));
		ans[x].erase(ans[x].find(a[y].ans));
		get(x);
	}

	void access(int x) {
		int y=0;
		for(;x;y=x,x=p[x]) {
			splay(x,0);
			if (t[x][1]) {
				add(x,t[x][1]);
				f[t[x][1]]=0;p[t[x][1]]=x;
			}
			if (y) {
				del(x,y);
				f[y]=x;p[y]=0;
			}
			t[x][1]=y;
			upd(x);
		}
	}

	void make_root(int x) {access(x);splay(x,0);reverse(x);}

	void link(int u,int v) {
		make_root(u);make_root(v);
		p[v]=u;add(u,v);upd(u);
	}

	bool check(int u,int v) {
		make_root(u);access(v);
		splay(v,0);
		for(;u&&u!=v;u=f[u]);
		return u==v;
	}
}

int n;
char opt[5];

int main() {
	n=read();
	fo(i,1,n) {
		LCT::pre[i].insert(Path(i,i,0));
		LCT::ans[i].insert(Path(i,i,0));
		LCT::get(i);LCT::upd(i);
	}
	fo(i,1,n-1) {
		int x=read(),y=read(),z=read(),v=i+n;
		LCT::val[v]=z;
		LCT::pre[v].insert(Path(0,0,-inf));
		LCT::ans[v].insert(Path(0,0,-inf));
		LCT::get(v);LCT::upd(v);
		if (LCT::check(x,y)) continue;
		LCT::link(x,v);LCT::link(v,y);
	}
	for(int q=read();q;q--) {
		scanf("%s",opt);
		if (opt[0]=='C') {
			int x=read()+n,y=read();
			LCT::make_root(x);LCT::access(x);
			LCT::val[x]=y;LCT::get(x);LCT::upd(x);
		}
		if (opt[0]=='Q') {
			int x=read();
			LCT::make_root(x);
			write(LCT::a[x].pre.w);
		}
	}
	return 0;
}

Light bulbs

离散化+差分tag

Code

#include <cstdio>
#include <cstring>
#include <algorithm>
#define fo(i,a,b) for(int i=a;i<=b;i++)
#define fd(i,a,b) for(int i=a;i>=b;i--)
using namespace std;

int read() {
	char ch;
	for(ch=getchar();ch<'0'||ch>'9';ch=getchar());
	int x=ch-'0';
	for(ch=getchar();ch>='0'&&ch<='9';ch=getchar()) x=x*10+ch-'0';
	return x;
}

const int N=1e3+5;

int n,q,ct,L[N],R[N],b[N<<2],c[N<<2],o;

void solve() {
	++ct;o=0;
	n=read();q=read();
	fo(i,1,q) {
		L[i]=read();R[i]=read()+1;
		b[++o]=L[i];b[++o]=R[i];
	}
	sort(b+1,b+o+1);o=unique(b+1,b+o+1)-b-1;
	fo(i,1,q) L[i]=lower_bound(b+1,b+o+1,L[i])-b,R[i]=lower_bound(b+1,b+o+1,R[i])-b;
	fo(i,1,q) c[L[i]]^=1,c[R[i]]^=1;
	fo(i,1,o) c[i]^=c[i-1];
	int ans=0;
	fo(i,1,o) ans+=c[i]*(b[i+1]-b[i]),c[i]=0;
	printf("Case #%d: %d\n",ct,ans);
}

int main() {
	for(int ty=read();ty;ty--) solve();
	return 0;
}

Triple

容易发现条件相当于三条边能够构成三角形(广义的,可以退化成一条线段
考虑枚举最大值ck,剩下的相当于求ai+bj>=ck且ai<=ck,bj<=ck的数量,注意相等的时候要特殊处理
由于值域是10^5直接上FFT就好了,不过由于数据组数过多当n小的时候要跑暴力
感谢ilnil的FHT板子(什么来着

Code

#include <cmath>
#include <vector>
#include <cstdio>
#include <cstring>
#include <algorithm>
#define fo(i,a,b) for(int i=a;i<=b;i++)
#define fd(i,a,b) for(int i=a;i>=b;i--)
using namespace std;

typedef double db;
typedef long long ll;

int read() {
	char ch;
	for(ch=getchar();ch<'0'||ch>'9';ch=getchar());
	int x=ch-'0';
	for(ch=getchar();ch>='0'&&ch<='9';ch=getchar()) x=x*10+ch-'0';
	return x;
}

const int N=2e5+5;

namespace FHT{
	#define fo(i,a,b)for(int i=a,_e=b;i<=_e;++i)
	#define ff(i,a,b)for(int i=a,_e=b;i<_e;++i)
	#define db double
	#define ll long long
	#define V vector<ll>
	const int M=(1<<21)+5;
	const db pi=acos(-1);
	int Q,h[M];
	db _c[M],_s[M],a[M],b[M],d[M],T1,T2;
	#define dxt(x,y)(x+=y,y=x-y*2)
	void dht(db *a,int sig){
		if(Q==1)return;
		ff(i,1,Q)if(h[i]>i)swap(a[i],a[h[i]]);
		for(int i=0;i<Q;i+=2)dxt(a[i],a[i+1]);
		int w1,w2,w3,w4;db T1,T2;
		for(int i=1,i2;(i2=i*2)<Q;i<<=1)for(int j=0;j<Q;j+=i*4){
			dxt(a[j],a[j+i2]);dxt(a[j+i],a[j+i*3]);
			ff(k,1,i){
				w1=j+k;w2=j+i2-k;w3=w1+i2;w4=w2+i2;
				T1=_c[i+k]*a[w3]+_s[i+k]*a[w4];
				T2=_s[i+k]*a[w3]-_c[i+k]*a[w4];
				a[w3]=a[w1]-T1;a[w1]+=T1;
				a[w4]=a[w2]-T2;a[w2]+=T2;
			}
		}
		if(sig){
			db y=1./Q;
			ff(i,0,Q)a[i]*=y;
		}
	}
	void init(int n){
		for(Q=1;Q<=n;Q<<=1);
		for(int i=1;i*2<Q;i<<=1)ff(j,0,i)_c[i+j]=cos(pi*j/(i*2)),_s[i+j]=sin(pi*j/(i*2));
	}
	V operator *(V aa,V bb){
		int na=aa.size()-1,nb=bb.size()-1;
		for(Q=1;Q<=na+nb;Q<<=1);
		ff(i,0,Q)h[i]=(h[i>>1]>>1)|(i&1?Q>>1:0),a[i]=b[i]=0;
		fo(i,0,na)a[i]=aa[i];
		fo(i,0,nb)b[i]=bb[i];
		dht(a,0);dht(b,0);
		d[0]=a[0]*b[0];
		ff(i,1,Q){
			T1=a[i];T2=a[Q-i];
			d[i]=(b[i]*(T1+T2)+b[Q-i]*(T1-T2))*0.5;
		}
		dht(d,1);
		vector<ll>c;c.resize(na+nb+1);
		fo(i,0,na+nb)c[i]=(ll)(d[i]+0.5);
		return c;
	}
}
using FHT::operator *;
using FHT::init;

int n,ct,a[N],b[N],c[N],ca[N],cb[N],cc[N];
ll cnt[N];

vector<ll> f,g,h;

ll calc(int *a,int *b,int *c) {
	ll ans=0;int j=0,k=0;
	fo(i,1,n) {
		while (j<n&&b[j+1]<a[i]) j++;
		while (k<n&&c[k+1]<a[i]) k++;
		ans+=(ll)j*k;
	}
	if (n<=1e3) {
		fo(i,1,a[n]) cnt[i]=0;
		fo(i,1,n) fo(j,1,n) cnt[b[i]+c[j]]++;
		fo(i,1,a[n]) cnt[i]+=cnt[i-1];
		fo(i,1,n) ans-=cnt[a[i]-1];
	} else {
		f.resize(b[n]+1);g.resize(c[n]+1);
		fo(i,0,b[n]) f[i]=0;
		fo(i,0,c[n]) g[i]=0;
		fo(i,1,n) f[b[i]]++,g[c[i]]++;
		h=f*g;
		h.resize(a[n]+1);
		fo(i,1,a[n]) h[i]+=h[i-1];
		fo(i,1,n) ans-=h[a[i]-1];
	}
	return ans;
}

void solve() {
	n=read();ct++;
	fo(i,1,n) a[i]=read();sort(a+1,a+n+1);
	fo(i,1,n) b[i]=read();sort(b+1,b+n+1);
	fo(i,1,n) c[i]=read();sort(c+1,c+n+1);
	fo(i,1,a[n]) ca[i]=0;
	fo(i,1,b[n]) cb[i]=0;
	fo(i,1,c[n]) cc[i]=0;
	fo(i,1,n) ca[a[i]]++,cb[b[i]]++,cc[c[i]]++;
	ll ans=0;
	// 一个最大值
	ans+=calc(a,b,c);
	ans+=calc(b,a,c);
	ans+=calc(c,a,b);
	// 两个最大值
	int j=0;
	fo(i,1,min(a[n],b[n])) {
		while (j<n&&c[j+1]<i) j++;
		ans+=(ll)ca[i]*cb[i]*j;
	}
	j=0;
	fo(i,1,min(a[n],c[n])) {
		while (j<n&&b[j+1]<i) j++;
		ans+=(ll)ca[i]*cc[i]*j;
	}
	j=0;
	fo(i,1,min(b[n],c[n])) {
		while (j<n&&a[j+1]<i) j++;
		ans+=(ll)cb[i]*cc[i]*j;
	}
	// 三个最大值
	fo(i,1,min(a[n],min(b[n],c[n]))) ans+=(ll)ca[i]*cb[i]*cc[i];
	printf("Case #%d: %lld\n",ct,ans);
}

int main() {
	init(2e5);
	for(int ty=read();ty;ty--) solve();
	return 0;
}

Counting Sequences II

设有a个偶数,b个奇数,考虑生成函数,答案显然是n![xn](ex+ex2)aexbn!*[x^n]({e^x+e^{-x}\over 2})^ae^{xb}
随便化一下就可以得到答案是12ai=0a(ai)(2ia+b)n{1\over 2^a}\sum_{i=0}^{a}\binom{a}{i}(2i-a+b)^n

Code

#include <cstdio>
#include <cstring>
#include <algorithm>
#define fo(i,a,b) for(int i=a;i<=b;i++)
#define fd(i,a,b) for(int i=a;i>=b;i--)
using namespace std;

typedef long long ll;

const int N=2e5+5,Mo=1e9+7,i2=Mo+1>>1;

int m,fac[N],inv[N];
ll n;

int pwr(int x,ll y) {
	int z=1;
	for(;y;y>>=1,x=(ll)x*x%Mo)
		if (y&1) z=(ll)z*x%Mo;
	return z;
}

void pre(int N) {
	fac[0]=1;fo(i,1,N) fac[i]=(ll)fac[i-1]*i%Mo;
	inv[N]=pwr(fac[N],Mo-2);fd(i,N-1,0) inv[i]=(ll)inv[i+1]*(i+1)%Mo;
}

int C(int m,int n) {return (ll)fac[m]*inv[n]%Mo*inv[m-n]%Mo;}

void solve() {
	scanf("%lld%d",&n,&m);
	int even=m/2,odd=m-even,ans=0;
	fo(i,0,even) {
		int p=2*i-even+odd;
		(ans+=(ll)pwr(p,n)*C(even,i)%Mo)%=Mo;
	}
	ans=(ll)ans*pwr(i2,even)%Mo;
	printf("%d\n",(ans+Mo)%Mo);
}

int main() {
	int ty;pre(2e5);
	for(scanf("%d",&ty);ty;ty--) solve();
	return 0;
}

Substring

考虑哈希,容易发现只需要知道头尾的字符和中间每种字符的出现次数,可以用一个10^5进制26位的数表示
并且对于原串S我们只需要维护一个前缀和就可以O(1)求一个子串的哈希值
由于询问串的和不大,询问串长的种类只有O(S)O(\sqrt |S|)种,也就是说原串中有用的子串只有O(nn)O(n\sqrt n)种,直接对于每一种都把哈希值求出来然后判一下就好了

Code

#include <vector>
#include <cstdio>
#include <cstring>
#include <algorithm>
#define fo(i,a,b) for(int i=a;i<=b;i++)
#define fd(i,a,b) for(int i=a;i>=b;i--)
using namespace std;

typedef long long ll;

const int N=1e5+5,P=1e5+7,M=1e6+7;
const ll Mo=23333333333333333;

int q,n,len[N],ord[N],cnt[M];
char st[N],s[N];
ll sum[N],ha[N],H[M],pw[N];
vector<int> p;

ll mult(ll x,ll y,ll Mo) {
	x%=Mo;y%=Mo;
	ll tmp=(ll)((long double)x*y/Mo+1e-8)*Mo;
	return (x*y-tmp+Mo)%Mo;
}

int Hash(ll x) {
	int t=x%M;
	while (H[t]!=-1&&H[t]!=x) t=(t+1)%M;
	return t;
}

bool cmp(int x,int y) {return len[x]<len[y];}

void solve() {
	scanf("%s",st+1);n=strlen(st+1);
	fo(i,1,n) sum[i]=(sum[i-1]+pw[st[i]-'a'])%Mo;
	scanf("%d",&q);p.clear();
	fo(i,1,q) {
		scanf("%s",s+1);
		len[i]=strlen(s+1);
		ha[i]=0;fo(j,2,len[i]-1) (ha[i]+=pw[s[j]-'a'])%=Mo;
		ll w=(s[1]-'a')*26+s[len[i]]-'a';
		(ha[i]+=mult(w,pw[26],Mo))%=Mo;
		int k=Hash(ha[i]);
		if (H[k]==-1) {H[k]=ha[i];p.push_back(k);}
	}
	fo(i,1,q) ord[i]=i;
	sort(ord+1,ord+q+1,cmp);
	for(int l=1,r=0;l<=q;l=r+1) {
		while (r<q&&len[ord[r+1]]==len[ord[l]]) r++;
		int L=len[ord[l]];
		fo(i,1,n-L+1) {
			int j=i+L-1;
			ll h=((sum[j-1]-sum[i])%Mo+Mo)%Mo,w=(st[i]-'a')*26+st[j]-'a';
			(h+=mult(w,pw[26],Mo))%=Mo;
			int k=Hash(h);if (H[k]==h) cnt[k]++;
		}
	}
	fo(i,1,q) printf("%d\n",cnt[Hash(ha[i])]);
	for(int i=0;i<p.size();i++) H[p[i]]=-1,cnt[p[i]]=0;
}

int main() {
	pw[0]=1;fo(i,1,26) pw[i]=mult(pw[i-1],P,Mo);
	fo(i,0,M-1) H[i]=-1,cnt[i]=0;
	int ty;for(scanf("%d",&ty);ty;ty--) solve();
	return 0;
}
©️2020 CSDN 皮肤主题: 编程工作室 设计师: CSDN官方博客 返回首页
实付0元
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值