TJOI2014

匹配

给出一个\(n(n\leq80)\)个点对\(n\)个点的带权二分图,求所有最大权匹配的交集。

先求出一个最大权匹配,然后枚举每一条匹配中的边,检验删除该边后是否还能形成最大权匹配。如果能则说明该边不在交集中,否则一定在交集中。

电源插排

一个长度为\(n(n\leq10^9)\)的插排,初始时是空的。进行\(Q(Q\leq10^5)\)次操作,操作有三种:

  • 向整个插排上最大的空区间(相等取最右)的中间(也取右)插上一个插头\(x\)
  • 询问区间\([L,R]\)中有几个插头。
  • 拔出插头\(x\)

用动态开点线段树来做即可。每条线段维护四个值:左起最长空区间的右端点,区间最长空区间的左、右端点,右起最长空区间的左端点。再记录一下插头\(x\)的位置就可以删除啦。

拼图

给出\(n(n\leq16)\)块四连通碎片,求有多少种方案将他们一起拼成一个\(4\times4\)的正方形。若没有,输出No Solution;只有一种,输出Yes, only one!和这个方案;否则输出Yes, many!

似乎直接爆搜即可,优化一点可以按块由大到小搜索,再优化可以搞搞状压什么的。

上升子序列

给出一个\(n(n\leq10^5)\)长度的数列,求该数列有多少个不同的长度至少为\(2\)的上升子序列,答案对\(10^9+7\)取模。两个子序列\(a,b\)被认为不同当且仅当\(\exists i,a_i \neq b_i\)

记录\(cnt[i]\)表示目前以数字\(i\)为结尾的不同上升子序列有多少个。当做到\(a_i\)时,\(cnt[a_i]\)变为\(1+\sum_{i=1}^{a[i]-1}cnt[i]\)个,额外的\(1\)表示只有一个数的序列\(\{a_i\}\),求和表示\(a_i\)能够接在多少个上升子序列后。要注意\(cnt[a_i]\)变为,而不是加上,因为如果存在\(a_{i'}=a_i(i'<i)\),那么以\(a_{i'}\)结尾的上升子序列一定出现在以\(a_i\)结尾的上升子序列中(把原序列中的\(a_{i'}\)换成\(a_i\))。
那么我们需要支持单点修改和前缀求和,可以用树状数组解决。

Alice and Bob

对于序列\(\{x_n\}(n\leq10^5)\),记\(a_i\)表示以\(x_i\)结尾的最长上升子序列长度,\(b_i\)表示以\(x_i\)开头的最长下降子序列长度。给出\({a_n}\),求\(\sum_{i=1}^nb_i\)的最大值。

若在\(a_1..a_{i-1}\)中有\(k\)个大于\(a_i\),那么说明在\(x_1..x_{i-1}\)中,至少有\(k\)个大于\(x_i\),至少有\(a_i-1\)个小于\(x_i\)

我没太看懂的题解:现在我们已知了一些大小关系。对于未知的关系,我们默认左边大于右边。构造序列并求\(\sum_{i=1}^nb_i\)即可。

电影评分

搞一个电影评分系统,进行\(n(n\leq10^4)\)次操作,操作有三种:

  • 发布一部编号为\(ID\)的电影,有\(x(x\leq5)\)个主演\(\{actor_x\}\),其评分为与其有共同主演的最新电影的评分,若没有则为\(0\)
  • 查询排名为\(x\)的电影的编号。排名以评分为第一关键字,发布时间为第二关键字。
  • 将电影\(ID\)的评分调整为原评分与\(x\)的平均数。

题解:将题目中的分数分为整数部分和小数部分,将小数部分写成二进制形式,此时可以使用后缀平衡树维护小数之间的大小关系。将小数部分和整数部分结合即可比较分数的大小关系。没大看懂,也不会后缀平衡树。

Code

//匹配
#include <cstdio>
#include <cstring>
#include <queue>
int const N=300;
int const INF=0x3F3F3F3F;
int min(int x,int y) {return x<y?x:y;}
int n;
int h[N],cnt;
struct edge{int u,v,c,w,nxt;} ed[N*N];
void edAdd(int u,int v,int c,int w)
{
    cnt++; ed[cnt].u=u,ed[cnt].v=v,ed[cnt].c=c,ed[cnt].w=w,ed[cnt].nxt=h[u],h[u]=cnt;
    cnt++; ed[cnt].u=v,ed[cnt].v=u,ed[cnt].c=0,ed[cnt].w=-w,ed[cnt].nxt=h[v],h[v]=cnt;
}
int s,t;
int dst[N],path[N];
std::queue<int> Q; bool inQ[N];
void clear() {for(int i=2;i<=cnt;i++) ed[i].c=i&1?0:ed[i].c+ed[i^1].c;}
bool SPFA()
{
    for(int u=s;u<=t;u++) dst[u]=-INF,path[u]=0;
    memset(inQ,false,sizeof inQ);
    dst[s]=0; Q.push(s),inQ[s]=true;
    while(!Q.empty())
    {
        int u=Q.front(); Q.pop(),inQ[u]=false;
        for(int i=h[u];i;i=ed[i].nxt)
        {
            int v=ed[i].v,w=ed[i].w;
            if(ed[i].c&&dst[u]+w>dst[v])
            {
                dst[v]=dst[u]+w,path[v]=i;
                if(!inQ[v]) Q.push(v),inQ[v]=true;
            }
        }
    }
    return dst[t]>-INF;
}
int maxFl()
{
    int cost=0;
    while(SPFA())
    {
        int fl=INF;
        for(int i=path[t];i;i=path[ed[i^1].v]) fl=min(fl,ed[i].c);
        for(int i=path[t];i;i=path[ed[i^1].v]) ed[i].c-=fl,ed[i^1].c+=fl;
        cost+=fl*dst[t];
    }
    return cost;
}
int cntM,M[N];
int main()
{
    freopen("match.in","r",stdin);
    freopen("match.out","w",stdout);
    scanf("%d",&n);
    s=0,t=n+n+1; cnt=1;
    for(int i=1;i<=n;i++)
        for(int j=1;j<=n;j++) {int x; scanf("%d",&x); edAdd(i,n+j,1,x);}
    for(int i=1;i<=n;i++) edAdd(s,i,1,0),edAdd(n+i,t,1,0);
    int ans=maxFl(); printf("%d\n",ans);
    cntM=0;
    for(int u=1;u<=n;u++)
        for(int i=h[u];i;i=ed[i].nxt) if(!ed[i].c&&ed[i].v!=s) M[++cntM]=i;
    for(int k=1;k<=cntM;k++)
    {
        clear(),ed[M[k]].c=0;
        int cost=maxFl();
        ed[M[k]].c=1;
        if(cost<ans) printf("%d %d\n",ed[M[k]].u,ed[M[k]].v-n);
    }
    return 0;
}
//电源插排
#include <cstdio>
#include <algorithm>
#include <map>
using namespace std;
inline char gc()
{
    static char now[1<<16],*S,*T;
    if(S==T) {T=(S=now)+fread(now,1,1<<16,stdin); if(S==T) return EOF;}
    return *S++;
}
inline int read()
{
    int x=0; char ch=gc();
    while(ch<'0'||'9'<ch) ch=gc();
    while('0'<=ch&&ch<='9') x=x*10+ch-'0',ch=gc();
    return x;
}
int const Q=1e5+10;
int n,q; map<int,int> pos;
#define s sg[s0]
int rt,sgCnt;
struct seg{int eptL0,eptR0,eptL,eptR,sum; int Lc,Rc;} sg[40*Q];
void create(int s0,int L0,int R0) {s.eptL0=s.eptR=R0,s.eptR0=s.eptL=L0,s.sum=0;}
void update(int s0,int L0,int R0)
{
    int mid=L0+R0>>1; seg Ls=sg[s.Lc],Rs=sg[s.Rc];
    s.eptL0=Ls.eptL0; if(Ls.eptL0==mid) s.eptL0=Rs.eptL0;
    s.eptR0=Rs.eptR0; if(Rs.eptR0==mid+1) s.eptR0=Ls.eptR0;
    int len1=Ls.eptR-Ls.eptL+1,len2=Rs.eptL0-Ls.eptR0+1,len3=Rs.eptR-Rs.eptL+1;
    int mx=max(len2,max(len1,len3));
    if(len3==mx) s.eptL=Rs.eptL,s.eptR=Rs.eptR;
    else if(len2==mx) s.eptL=Ls.eptR0,s.eptR=Rs.eptL0;
    else if(len1==mx) s.eptL=Ls.eptL,s.eptR=Ls.eptR;
    s.sum=Ls.sum+Rs.sum;
}
int L,R;
void add(int s0,int L0,int R0,int v)
{
    if(L<=L0&&R0<=R)
    {
        s.sum=v;
        if(v==1) s.eptL0=L0-1,s.eptR0=R0+1,s.eptL=L0+1,s.eptR=L0;
        else s.eptL0=s.eptR0=s.eptL=s.eptR=L0;
        return;
    }
    int mid=L0+R0>>1;
    if(!s.Lc) create(s.Lc=++sgCnt,L0,mid);
    if(!s.Rc) create(s.Rc=++sgCnt,mid+1,R0);
    if(L<=mid) add(s.Lc,L0,mid,v); if(mid<R) add(s.Rc,mid+1,R0,v);
    update(s0,L0,R0);
}
int query(int s0,int L0,int R0)
{
    if(s0==0) return 0;
    if(L<=L0&&R0<=R) return s.sum;
    int mid=L0+R0>>1; int res=0;
    if(L<=mid) res+=query(s.Lc,L0,mid);
    if(mid<R) res+=query(s.Rc,mid+1,R0);
    return res;
}
int main()
{
    freopen("switch.in","r",stdin);
    freopen("switch.out","w",stdout);
    n=read(),q=read();
    create(rt=++sgCnt,1,n);
    for(int i=1;i<=q;i++)
    {
        int k=read();
        if(k==0) {L=read(),R=read(); printf("%d\n",query(rt,1,n));}
        else
        {   
            L=R=(sg[rt].eptL+sg[rt].eptR-1)/2+1;
            if(pos[k]) L=R=pos[k],add(rt,1,n,0),pos[k]=0;
            else add(rt,1,n,1),pos[k]=L;
        }
    }
    return 0;
}
//上升子序列
#include <cstdio>
#include <algorithm>
using namespace std;
int const N=1e5+10;
int const H=1e9+7;
int n,a[N]; int n0,map[N];
int tr[N];
void add(int x,int v) {while(x<=n0) tr[x]=(tr[x]+v)%H,x+=x&(-x);}
int sum(int x) {int res=0; while(x) res=(res+tr[x])%H,x-=x&(-x); return res;}
int pre[N];
int main()
{
    freopen("subsequence.in","r",stdin);
    freopen("subsequence.out","w",stdout);
    scanf("%d",&n);
    for(int i=1;i<=n;i++) scanf("%d",&a[i]),map[i]=a[i];
    sort(map+1,map+n+1); n0=unique(map+1,map+n+1)-(map+1);
    for(int i=1;i<=n;i++) a[i]=lower_bound(map+1,map+n0+1,a[i])-map;
    for(int i=1;i<=n0;i++) pre[i]=0;
    for(int i=1;i<=n;i++)
    {
        int res=sum(a[i]-1)+1;
        add(a[i],res-pre[a[i]]); pre[a[i]]=res;
    }
    printf("%d\n",sum(n0)-n0);
    return 0;
}
posted @ 2018-03-12 22:54  VisJiao  阅读(314)  评论(0编辑  收藏  举报