D1T1:
斯波离散化+并查集题不解释。
#include <bits/stdc++.h>
#define ll long long
#define gc getchar()
#define pb push_back
#define N 100009
using namespace std;
ll n,c[N],father[N];
ll a[N],b[N];
vector<ll> p;
ll getfather(ll x)
{
return father[x]==x?x:father[x]=getfather(father[x]);
}
ll read()
{
ll x;
scanf("%lld",&x);
return x;
}
int main()
{
ll T=read();
while (T--)
{
bool flag=1;
n=read(),p.clear();
for (ll i=1;i<=n;i++)
{
a[i]=read(),b[i]=read(),c[i]=read();
p.pb(a[i]),p.pb(b[i]);
}
sort(p.begin(),p.end());
p.erase(unique(p.begin(),p.end()),p.end());
for (ll i=1;i<=p.size();i++) father[i]=i;
for (ll i=1;i<=n;i++)
{
a[i]=lower_bound(p.begin(),p.end(),a[i])-p.begin()+1;
b[i]=lower_bound(p.begin(),p.end(),b[i])-p.begin()+1;
if (c[i])
{
ll x=getfather(a[i]),y=getfather(b[i]);
if (x!=y) father[x]=y;
}
}
for (ll i=1;i<=p.size();i++) father[i]=getfather(i);
for (ll i=1;i<=n;i++)
if (!c[i]&&father[a[i]]==father[b[i]])
{
flag=0;
break;
}
puts(flag?"YES":"NO");
}
return 0;
}
D2T2
认真(sui bian)撕烤后,发现可以树链剖分。然后就是一道模板题。(一遍ce一遍A)
#include <bits/stdc++.h>
#define ll long long
#define gc getchar()
#define pb push_back
#define N 100009
#define root 1,1,n
#define NOW int cur,int l,int r
#define mid (l+r>>1)
#define lc cur<<1
#define rc lc|1
#define lson lc,l,mid
#define rson rc,mid+1,r
#define now cur,l,r
using namespace std;
int n,m,a[N],first[N],number,x,father[N],top[N],size[N],Mson[N];
int dfn[N],deep[N],ed[N],cnt,sum[N<<2],tg[N<<2];
struct edge
{
int to,next;
void add(int x,int y)
{
to=y,next=first[x],first[x]=number;
}
}e[N];
int read()
{
int x=1;
char ch;
while (ch=gc,ch<'0'||ch>'9') if (ch=='-') x=-1;
int s=ch-'0';
while (ch=gc,ch>='0'&&ch<='9') s=s*10+ch-'0';
return s*x;
}
void Dfs(int x,int y)
{
top[x]=y;
dfn[x]=++cnt;
if (Mson[x]) Dfs(Mson[x],y);
for (int i=first[x];i;i=e[i].next)
if (e[i].to!=Mson[x]) Dfs(e[i].to,e[i].to);
ed[x]=cnt;
}
void dfs(int x,int fa)
{
size[x]=1;
father[x]=fa;
deep[x]=deep[fa]+1;
for (int i=first[x];i;i=e[i].next)
{
dfs(e[i].to,x);
size[x]+=size[e[i].to];
if (size[e[i].to]>size[Mson[x]]) Mson[x]=e[i].to;
}
}
void up(NOW)
{
sum[cur]=sum[lc]+sum[rc];
}
void down(NOW)
{
if (tg[cur])
{
sum[lc]=(mid-l+1)*(tg[cur]-1);
tg[lc]=tg[cur];
sum[rc]=(r-mid)*(tg[cur]-1);
tg[rc]=tg[cur];
tg[cur]=0;
}
}
void ins(NOW,int L,int R,int x)
{
if (L<=l&&R>=r)
{
tg[cur]=x+1;
sum[cur]=x*(r-l+1);
return;
}
down(now);
if (L<=mid) ins(lson,L,R,x);
if (R>mid) ins(rson,L,R,x);
up(now);
}
void Ins(int x)
{
for (;top[x]!=0;x=father[top[x]])
ins(root,dfn[top[x]],dfn[x],1);
ins(root,dfn[1],dfn[x],1);
}
int qry(NOW,int L,int R)
{
if (L<=l&&R>=r) return sum[cur];
down(now);
int ans=0;
if (L<=mid) ans+=qry(lson,L,R);
if (R>mid) ans+=qry(rson,L,R);
up(now);
return ans;
}
int qry(int x)
{
int ans=0;
for (;top[x]!=0;x=father[top[x]])
ans+=qry(root,dfn[top[x]],dfn[x]);
ans+=qry(root,dfn[1],dfn[x]);
return ans;
}
int main()
{
n=read();
for (int i=2;i<=n;i++) e[++number].add(x=read()+1,i);
dfs(1,0);
Dfs(1,0);
m=read();
for (int i=1;i<=m;i++)
{
char ch;
while (ch=gc,ch!='i'&&ch!='u');
x=read()+1;
if (ch=='i')
{
printf("%d\n",deep[x]-qry(x));
Ins(x);
}
else
{
printf("%d\n",qry(root,dfn[x],ed[x]));
ins(root,dfn[x],ed[x],0);
}
}
return 0;
}
D1T3:
首先小于根号500的素数只有8个,状压记录两个人各选了其中的哪几个。然后分解后有大质数的可以按大质数分类(没大质数的每个自成一类),这样显然可以一一对应,每类显然都只能一个人选,然后dp转移一下。
g[0][i][j]表示当前第一个人选择,第一个人选了集合为i的素数,第二个选了j的方案数。g[1][i][j]同理。
然后f[i][j]表示第一个人选了集合为i的素数,第二个选了j的方案数的总方案数。注意每次减掉两个人这轮都没有选的情况,就是减掉原来的f[i][j]。然后累加就好了。。
#include <bits/stdc++.h>
#define gc getchar()
#define N 509
using namespace std;
const int pri[8]={2,3,5,7,11,13,17,19};
pair<int,int> p[N];
int n,mod,f[1<<8][1<<8],g[2][1<<8][1<<8];
int read()
{
int x=1;
char ch;
while (ch=gc,ch<'0'||ch>'9') if (ch=='-') x=-1;
int s=ch-'0';
while (ch=gc,ch>='0'&&ch<='9') s=s*10+ch-'0';
return s*x;
}
int main()
{
n=read(),mod=read();
for (int i=2;i<=n;i++)
{
int now=i;
for (int j=0;j<8;j++)
if (i%pri[j]==0)
{
p[i].second|=1<<j;
while (now%pri[j]==0) now/=pri[j];
}
p[i].first=now;
}
sort(p+2,p+n+1);
f[0][0]=1;
for (int i=2;i<=n;i++)
{
if (p[i].first!=p[i-1].first||p[i].first==1)
{
memcpy(g[0],f,sizeof(g[0]));
memcpy(g[1],f,sizeof(g[1]));
}
for (int j=(1<<8)-1;j>=0;j--)
for (int k=(1<<8)-1;k>=0;k--)
{
if ((j&p[i].second)==0)
g[1][j][k|p[i].second]=(g[1][j][k|p[i].second]+g[1][j][k])%mod;
if ((k&p[i].second)==0)
g[0][j|p[i].second][k]=(g[0][j|p[i].second][k]+g[0][j][k])%mod;
}
if (p[i].first!=p[i+1].first||p[i].first==1)
for (int j=0;j<(1<<8);j++)
for (int k=0;k<(1<<8);k++)
f[j][k]=((g[0][j][k]+g[1][j][k])%mod-f[j][k]+mod)%mod;
}
int ans=0;
for (int i=0;i<(1<<8);i++)
for (int j=0;j<(1<<8);j++)
if ((i&j)==0) ans=(ans+f[i][j])%mod;
printf("%d\n",ans);
return 0;
}
D2T1:
其实就是一个k叉哈夫曼树,每次都挑选其中最小的k个合并为一个再加进去,然后发现这样(n-1)%(k-1)!=0就很尴尬,然而其实很简单,加上几个(搞笑的)节点权值为零就好。
然后考虑如何让深度最小,其实也就是当权值相同时挑选深度较小的合并就好啦。优先队列<号重载就好啦。
#include <bits/stdc++.h>
#define gc getchar()
#define N 100009
#define ll long long
using namespace std;
ll n,k,w[N],cnt,Ans;
struct node
{
ll val,deep;
node(ll val=0,ll deep=0):val(val),deep(deep){}
};
bool operator <(const node &x,const node &y)
{
return x.val>y.val||(x.val==y.val&&x.deep>y.deep);
}
priority_queue<node> p;
ll read()
{
ll x=1;
char ch;
while (ch=gc,ch<'0'||ch>'9') if (ch=='-') x=-1;
ll s=ch-'0';
while (ch=gc,ch>='0'&&ch<='9') s=s*10+ch-'0';
return s*x;
}
int main()
{
n=read(),k=read();
for (ll i=1;i<=n;i++) w[i]=read(),p.push(node(w[i],1)),++cnt;
if ((n-1)%(k-1)!=0)
for (ll i=1;i<=k-1-(n-1)%(k-1);i++)
p.push(node(0,1)),++cnt;
while (cnt>1)
{
ll sum=0,Max_deep=0;
for (ll i=1;i<=k;i++)
{
sum+=p.top().val;
Max_deep=max(Max_deep,p.top().deep);
p.pop();
}
Ans+=sum;
p.push(node(sum,Max_deep+1));
cnt-=k-1;
}
printf("%lld\n%lld\n",Ans,p.top().deep-1);
return 0;
}
D2T2:
发现就是求后缀中lcp>=l的对数和最大的权值积。
lcp可以想到后缀数组中height数组取最小值就好了。
从大到小加入,每次合并两边的区间,维护答案,然后对于对数差分一下,最大权值积只要每个区间维护最大最小值(因为有负的!!)就好啦。
#include <bits/stdc++.h>
#define gc getchar()
#define N 300009
#define ll long long
using namespace std;
ll n,f[N],a[N],pos[N],fa[N],Ans[N],sum[N];
struct node
{
ll number,Max,Min,pre,next;
node(ll number=0,ll Max=0,ll Min=0,ll pre=0,ll next=0):number(number),Max(Max),Min(Min),pre(pre),next(next){}
}p[N];
ll read()
{
ll x=1;
char ch;
while (ch=gc,ch<'0'||ch>'9') if (ch=='-') x=-1;
ll s=ch-'0';
while (ch=gc,ch>='0'&&ch<='9') s=s*10+ch-'0';
return s*x;
}
ll sa[N],Rank[N],height[N];
ll wa[N],wb[N],wv[N],wd[N];
bool cmp(ll *r,ll a,ll b,ll l)
{
return r[a]==r[b]&&r[a+l]==r[b+l];
}
void da(ll *r,ll n,ll m)
{
ll *x=wa,*y=wb,*t;
for (ll i=0;i<m;i++) wd[i]=0;
for (ll i=0;i<n;i++) wd[x[i]=r[i]]++;
for (ll i=1;i<m;i++) wd[i]+=wd[i-1];
for (ll i=n-1;i>=0;i--) sa[--wd[x[i]]]=i;
for (ll j=1,p=1,i;p<n;j<<=1,m=p)
{
for (p=0,i=n-j;i<n;i++) y[p++]=i;
for (i=0;i<n;i++) if (sa[i]>=j) y[p++]=sa[i]-j;
for (i=0;i<n;i++) wv[i]=x[y[i]];
for (i=0;i<m;i++) wd[i]=0;
for (i=0;i<n;i++) wd[wv[i]]++;
for (i=1;i<m;i++) wd[i]+=wd[i-1];
for (i=n-1;i>=0;i--) sa[--wd[wv[i]]]=y[i];
for (t=x,x=y,y=t,p=1,x[sa[0]]=0,i=1;i<n;i++)
x[sa[i]]=cmp(y,sa[i-1],sa[i],j)?p-1:p++;
}
}
void get_height(ll *r,ll n)
{
for (ll i=1;i<=n;i++) Rank[sa[i]]=i;
for (ll i=0,k=0,j;i<n;height[Rank[i++]]=k)
for (k?k--:0,j=sa[Rank[i]-1];r[i+k]==r[j+k];k++);
}
bool cm(ll x,ll y)
{
return height[x]>height[y];
}
ll getfa(ll x)
{
return fa[x]==x?x:fa[x]=getfa(fa[x]);
}
int main()
{
freopen("savour9.in","r",stdin);
freopen("savour.out","w",stdout);
n=read();
for (ll i=0;i<n;i++)
{
char ch;
while (ch=gc,ch<'a'||ch>'z');
a[i]=ch-'a'+1;
}
a[n]=0;
da(a,n+1,27);
for (ll i=0;i<n;i++)
pos[i+1]=i+1,f[i]=read(),sum[i]=-9223372036854775800ll;
sum[n]=sum[n-1];
get_height(a,n);
sort(pos+1,pos+n+1,cm);
ll now=1;
p[0].next=1;
for (ll i=1;i<=n;i++)
p[i]=node(1,f[sa[i]],f[sa[i]],i-1,i+1),fa[i]=i;
p[n+1].pre=n;
for (ll i=n-1;i>=0;i--)
{
while (height[pos[now]]>=i&&now<=n)
{
if (pos[now]<=1)
{
now++;
continue;
}
node tmp;
ll x=getfa(pos[now]),y=getfa(pos[now]-1);
Ans[i]+=p[x].number*p[y].number;
sum[i]=max(sum[i],p[x].Max*p[y].Max);
sum[i]=max(sum[i],p[x].Max*p[y].Min);
sum[i]=max(sum[i],p[x].Min*p[y].Max);
sum[i]=max(sum[i],p[x].Min*p[y].Min);
tmp.number=p[x].number+p[y].number;
tmp.Max=max(p[x].Max,p[y].Max);
tmp.Min=min(p[x].Min,p[y].Min);
tmp.pre=p[y].pre;
tmp.next=p[x].next;
p[p[y].pre].next=x;
p[x]=tmp;
fa[y]=x;
now++;
}
}
for (ll i=n-1;i>=0;i--)
Ans[i]+=Ans[i+1],sum[i]=max(sum[i],sum[i+1]);
for (ll i=0;i<n;i++)
printf("%lld %lld\n",Ans[i],Ans[i]==0?0:sum[i]);
return 0;
}
D2T3:
首先对于每个点 根据x,x+y,x-y的值可以分类,每种离散化一下,
类相同的之间可以连边,当然x相同的也行。(写完突然消失了不开心,就只好简单讲了。。。)
第一问:
dp出通过向上的三种方式到达的最大值(用前缀,后缀最大值优化一下),然后统计答案。
第二问:
第一问dp时用pre数组记录上一个走的点,然后倒推回去就好了(注意同一行左右的前后顺序)
第三问:
把两个通过第一题三种转移方法到达的,且答案等于第一问的 点对连边(下界:1,上界:inf)
源点汇点跟每个点连下边,因为肯定可行,所以直接跑最大流,然后sum-最大流就是答案啦(最小流)
#include <bits/stdc++.h>
#define gc getchar()
#define N 50009
#define inf 2147483647
using namespace std;
int n,f[N],beg[N],ed[N],s[3][N],pre[3][N],cnt,pl[N];
int Maxl[N],Maxlnum[N],Maxr[N],Maxrnum[N];
int S,T,SS,TT,pd[N],pdl[N],pdr[N],du[N],dn[N],sum;
struct node
{
int x,y,lei[3],num;
}p[N];
vector<int> link[3],Y;
bool operator <(const node &a,const node &b)
{
return a.y<b.y||(a.y==b.y&&a.x<b.x);
}
struct edge
{
int from,to,cap,flow;
edge(int u,int v,int c,int f):from(u),to(v),cap(c),flow(f){}
};
vector<edge> e;
vector<int> G[N];
int d[N],cur[N];
bool vis[N];
int read()
{
char ch;
int x=1;
while (ch=gc,ch<'0'||ch>'9') if (ch=='-') x=-1;
int s=ch-'0';
while (ch=gc,ch>='0'&&ch<='9') s=s*10+ch-'0';
return s*x;
}
void add(int from,int to,int cap)
{
e.push_back(edge(from,to,cap,0));
e.push_back(edge(to,from,0,0));
int m=e.size();
G[from].push_back(m-2);
G[to].push_back(m-1);
}
#define E e[G[x][i]]
bool bfs(int s,int t)
{
memset(vis,0,sizeof(vis));
queue<int> Q;
Q.push(s);
d[s]=0;
vis[s]=1;
while (!Q.empty())
{
int x=Q.front();
Q.pop();
for (int i=0;i<G[x].size();i++)
if (!vis[E.to]&&E.cap>E.flow)
{
vis[E.to]=1;
d[E.to]=d[x]+1;
Q.push(E.to);
}
}
return vis[t];
}
int dfs(int x,int a,int s,int t)
{
if (x==t||a==0) return a;
int flow=0,f;
for (int &i=cur[x];i<G[x].size();i++)
if (d[x]+1==d[E.to]&&(f=dfs(E.to,min(a,E.cap-E.flow),s,t))>0)
{
E.flow+=f;
e[G[x][i]^1].flow-=f;
flow+=f;
a-=f;
if (!a) break;
}
return flow;
}
int Maxflow(int s,int t)
{
int flow=0;
while (bfs(s,t))
{
memset(cur,0,sizeof(cur));
flow+=dfs(s,inf,s,t);
}
return flow;
}
#undef E
void Add(int x,int y,int Min,int Max)
{
du[x]-=Min,du[y]+=Min;
add(x,y,Max-Min);
}
int main()
{
n=read();
for (int i=1;i<=n;i++)
{
p[i].x=read(),p[i].y=read();
p[i].lei[0]=p[i].x-p[i].y;
p[i].lei[1]=p[i].x;
p[i].lei[2]=p[i].x+p[i].y;
p[i].num=i;
link[0].push_back(p[i].lei[0]);
link[1].push_back(p[i].lei[1]);
link[2].push_back(p[i].lei[2]);
Y.push_back(p[i].y);
}
n++;
sort(p+1,p+n+1);
for (int i=0;i<3;i++)
{
link[i].push_back(0);
sort(link[i].begin(),link[i].end());
link[i].erase(unique(link[i].begin(),link[i].end()),link[i].end());
}
Y.push_back(0);
sort(Y.begin(),Y.end());
Y.erase(unique(Y.begin(),Y.end()),Y.end());
for (int i=1;i<=n;i++)
{
for (int j=0;j<3;j++)
p[i].lei[j]=lower_bound(link[j].begin(),link[j].end(),p[i].lei[j])-link[j].begin()+1;
p[i].y=lower_bound(Y.begin(),Y.end(),p[i].y)-Y.begin()+1;
if (!beg[p[i].y]) beg[p[i].y]=i;
ed[p[i].y]=i;
}
for (int i=2;i<=n;i++) f[i]=-1;
for (int i=0;i<3;i++)
s[i][lower_bound(link[i].begin(),link[i].end(),0)-link[i].begin()+1]=1;
Maxl[1]=-1,Maxlnum[1]=1,Maxr[1]=1,Maxrnum[1]=1;
for (int i=2;i<=(int)Y.size();i++)
{
for (int j=beg[i];j<=ed[i];j++)
for (int k=0;k<3;k++)
{
if (s[k][p[j].lei[k]]>0)
{
int u=s[k][p[j].lei[k]];
pre[k][j]=u;
if (f[u]!=-1) f[j]=max(f[j],f[u]+1);
if (u!=beg[p[u].y]&&Maxlnum[u-1]>0)
f[j]=max(f[j],Maxl[u-1]+u-beg[p[u].y]+1);
if (u!=ed[p[u].y]&&Maxrnum[u+1]>0)
f[j]=max(f[j],Maxr[u+1]+ed[p[u].y]-u+1);
}
s[k][p[j].lei[k]]=j;
}
if (f[beg[i]]>0)
{
Maxl[beg[i]]=f[beg[i]];
Maxlnum[beg[i]]=beg[i];
}
for (int j=beg[i]+1;j<=ed[i];j++)
{
Maxl[j]=Maxl[j-1],Maxlnum[j]=Maxlnum[j-1];
if ((f[j]>=Maxl[j]||Maxlnum[j]==0)&&f[j]>0)
{
Maxl[j]=f[j];
Maxlnum[j]=j;
}
}
if (f[ed[i]]>0)
{
Maxr[ed[i]]=f[ed[i]];
Maxrnum[ed[i]]=ed[i];
}
for (int j=ed[i]-1;j>=beg[i];j--)
{
Maxr[j]=Maxr[j+1],Maxrnum[j]=Maxrnum[j+1];
if ((f[j]>=Maxr[j]||Maxrnum[j]==0)&&f[j]>0)
{
Maxr[j]=f[j];
Maxrnum[j]=j;
}
}
}
int ans=0,now=1;
for (int i=2;i<=n;i++)
if (f[i]+ed[p[i].y]-beg[p[i].y]>ans)
{
ans=f[i]+ed[p[i].y]-beg[p[i].y];
now=i;
}
printf("%d\n",ans);//Max trees
for (int i=ed[p[now].y];i>now;i--) pl[++cnt]=p[i].num;
for (int i=beg[p[now].y];i<now;i++) pl[++cnt]=p[i].num;
while (now!=1)
{
pl[++cnt]=p[now].num;
for (int k=0;k<3;k++)
{
int u=pre[k][now];
if (u>0)
{
if (f[u]+1==f[now])
{
now=u;
break;
}
if (u!=beg[p[u].y]&&Maxl[u-1]+u-beg[p[u].y]+1==f[now]&&Maxlnum[u-1]>0)
{
for (int i=u;i>Maxlnum[u-1];i--) pl[++cnt]=p[i].num;
for (int i=beg[p[u].y];i<Maxlnum[u-1];i++) pl[++cnt]=p[i].num;
now=Maxlnum[u-1];
break;
}
if (u!=ed[p[u].y]&&Maxr[u+1]+ed[p[u].y]-u+1==f[now]&&Maxrnum[u+1]>0)
{
for (int i=u;i<Maxrnum[u+1];i++) pl[++cnt]=p[i].num;
for (int i=ed[p[u].y];i>Maxrnum[u+1];i--) pl[++cnt]=p[i].num;
now=Maxrnum[u+1];
break;
}
}
}
}
for (int i=cnt;i>=1;i--)
printf("%d%s",pl[i],i==1?"\n":" ");//print out plans
for (int i=2;i<=n;i++)
if (f[i]+ed[p[i].y]-beg[p[i].y]==ans) pd[i]=1;
S=n+1,T=n+2,SS=n+3,TT=n+4;
for (int i=(int)Y.size();i;i--)
{
int bjm=n+1;
for (int j=ed[i];j>=beg[i];j--)
{
if (pdl[j]) bjm=Maxl[j];
if (bjm==f[j]) pd[j]=1;
}
bjm=n+1;
for (int j=beg[i];j<=ed[i];j++)
{
if (pdr[j]) bjm=Maxr[j];
if (bjm==f[j]) pd[j]=1;
}
for (int j=beg[i];j<=ed[i];j++)
{
if (!pd[j]) continue;
for (int k=0;k<3;k++)
{
int u=pre[k][j];
if (!u) continue;
bool flag=0;
if (f[u]+1==f[j])
{
pd[u]=1;
flag=1;
}
if (u!=beg[p[u].y]&&Maxl[u-1]+u-beg[p[u].y]+1==f[j]&&Maxlnum[u-1]>0)
{
pdl[u-1]=1;
flag=1;
}
if (u!=ed[p[u].y]&&Maxr[u+1]+ed[p[u].y]-u+1==f[j]&&Maxrnum[u+1]>0)
{
pdr[u+1]=1;
flag=1;
}
if (flag) Add(u,j,1,inf);//u is past
}
}
}
for (int i=1;i<=n;i++)
{
add(S,i,inf);
add(i,T,inf);
if (du[i]>0) add(SS,i,du[i]),sum+=du[i];
else if (du[i]<0) add(i,TT,-du[i]);
}
int flow=Maxflow(SS,TT);
printf("%d\n",sum-flow);
return 0;
}