[CLYZ2017]day8


异色弧

solution

70分

\(Let's\;orz\) BearChild!

朗格拉姆计数

solution

60分

将环复制两遍,预处理出前\(i\)个数中比\(j\)大的数的个数 ,枚举\(a,b\),答案加上\(c\)的个数.

#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define N 5001
#define M 10001
using namespace std;
typedef long long ll;
//s[i][j]表示前i个数中比j大的数的个数 
ll ans;
int s[M][N],a[M],n;
inline int read(){
    int ret=0;char c=getchar();
    while(!isdigit(c))
        c=getchar();
    while(isdigit(c)){
        ret=(ret<<1)+(ret<<3)+c-'0';
        c=getchar();
    }
    return ret;
}
inline void Aireen(){
    scanf("%d",&n);
    for(int i=1;i<=n;++i)
        scanf("%d",&a[i]);
    for(int i=1;i<=n;++i)
        a[i+n]=a[i];
    for(int j=1;j<=n;++j)
        for(int i=1;i<=(n<<1);++i){
            s[i][j]=s[i-1][j];
            if(a[i]>j) ++s[i][j];
        }
    for(int i=1;i<=n;++i)
        for(int j=i;ja[i]){
                ans+=(ll)(s[i+n-1][a[j]]-s[j][a[j]]);
            }
    printf("%lld\n",ans);
}
int main(){
    freopen("counter.in","r",stdin);
    freopen("counter.out","w",stdout);
    Aireen();
    fclose(stdin);
    fclose(stdout);
    return 0;
}

100分

三元组的形式为\(123,231,312\).
\(231=XX1-321\).
\(312=3XX-321\).
树状数组或线段树维护即可.

#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define N 200005
using namespace std;
typedef long long ll;
ll ans;
int a[N],s[N],g[N],fr[N],be[N],n;
inline int read(){
    int ret=0;char c=getchar();
    while(!isdigit(c))
        c=getchar();
    while(isdigit(c)){
        ret=(ret<<1)+(ret<<3)+c-'0';
        c=getchar();
    }
    return ret;
}
inline int lowbit(int x){
    return x&(-x);
}
inline void add(int k){
    for(int i=k;i<=n;i+=lowbit(i))
        ++s[i];
}
inline int ask(int k){
    int ret=0;
    for(int i=k;i;i-=lowbit(i))
        ret+=s[i];
    return ret;
}
inline ll c(int k){
    return 1ll*k*(k-1)>>1ll;
} 
inline void Aireen(){
    n=read();
    for(int i=1;i<=n;++i){
        a[i]=read();g[a[i]]=i;
    }
    for(int i=1;i<=n;++i){
        fr[i]=ask(g[i]-1);
        be[i]=ask(n)-ask(g[i]);
        add(g[i]);
    }
    memset(s,0,sizeof(s));
    for(int i=n,f,b;i;--i){
        f=ask(g[i]-1);
        b=ask(n)-ask(g[i]);
        add(g[i]);
        ans+=1ll*fr[i]*b;//123
        ans+=c(be[i])-1ll*f*be[i];//312
        ans+=c(f)-1ll*f*be[i];//231 
    }
    printf("%lld\n",ans);
}
int main(){
    freopen("counter.in","r",stdin);
    freopen("counter.out","w",stdout);
    Aireen();
    fclose(stdin);
    fclose(stdout);
    return 0;
}

修路

solution

斯坦纳树

\(f[i][j]\)表示以\(i\)为根的树中,连通的节点的状态为\(j\)的最小/大权值.
\(f[i][j]=min\{f[i][l]+f[i][l^j]\}\),\(l\)\(j\)的子集.
\(f[i][j]=min\{f[k][j]+g[k][i]\}\),这可以用\(spfa\)\(dijkstra\)求解.

100分

用斯坦纳树求出\(f[\;][\;]\)数组.
如果在状态\(j\)中,\(i\)\(n-i+1\)\(j\)中或都不在\(j\)中,\(g[j]=min\{f[i][j]\}\)(保证\(i\)\(n-i+1\)连通).
\(g[i]=min\{g[j]+g[i^j]\}j\)\(i\)的子集\()\).

#include
#include
#include
#include
#define K 8
#define N 10005
#define M 20005
#define INF 10000000
#define min(a,b) a