大概是第一场AK的ACM比赛?
我太菜了,队友太强了.jpg
先把自己负责的题写一写,剩下的咕了
题目链接
LCT模板题
对于每条偏爱路维护正着和反着两条直径,用两个set维护所有虚儿子的最长链
有板子就很舒服
#include
#include
#include
#include
#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;
}
离散化+差分tag
#include
#include
#include
#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;
}
容易发现条件相当于三条边能够构成三角形(广义的,可以退化成一条线段
考虑枚举最大值ck,剩下的相当于求ai+bj>=ck且ai<=ck,bj<=ck的数量,注意相等的时候要特殊处理
由于值域是10^5直接上FFT就好了,不过由于数据组数过多当n小的时候要跑暴力
感谢ilnil的FHT板子(什么来着
#include
#include
#include
#include
#include
#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
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;
}
设有a个偶数,b个奇数,考虑生成函数,答案显然是 n ! ∗ [ x n ] ( e x + e − x 2 ) a e x b n!*[x^n]({e^x+e^{-x}\over 2})^ae^{xb} n!∗[xn](2ex+e−x)aexb
随便化一下就可以得到答案是 1 2 a ∑ i = 0 a ( a i ) ( 2 i − a + b ) n {1\over 2^a}\sum_{i=0}^{a}\binom{a}{i}(2i-a+b)^n 2a1∑i=0a(ia)(2i−a+b)n
#include
#include
#include
#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;
}
考虑哈希,容易发现只需要知道头尾的字符和中间每种字符的出现次数,可以用一个10^5进制26位的数表示
并且对于原串S我们只需要维护一个前缀和就可以O(1)求一个子串的哈希值
由于询问串的和不大,询问串长的种类只有 O ( ∣ S ∣ ) O(\sqrt |S|) O(∣S∣)种,也就是说原串中有用的子串只有 O ( n n ) O(n\sqrt n) O(nn)种,直接对于每一种都把哈希值求出来然后判一下就好了
#include
#include
#include
#include
#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;
}