湘潭邀请赛 2017 题解

E :Partial Sum

  每次取任意两个不同的前缀,取过之后不能再取,最多取M次

  将前缀和排序,优先取最大,最小就行了

#include<bits/stdc++.h>
using namespace std;
#pragma comment(linker, "/STACK:102400000,102400000")
#define ls i<<1
#define rs ls | 1
#define mid ((ll+rr)>>1)
#define pii pair<int,int>
#define MP make_pair
typedef long long LL;
const long long INF = 1e18+1LL;
const double Pi = acos(-1.0);
const int N = 5e5+10, M = 1e3+20, mod = 1e9+7,inf = 2e9;

int n,m,c,sum[N],a[N],b[N];
int main() {
    while(scanf("%d%d%d",&n,&m,&c)!=EOF) {
        sum[0] = 0;
        int cnt =0;
        b[++cnt] = 0;
        for(int i = 1; i <= n; ++i) {
          scanf("%d",&a[i]);
          sum[i] = sum[i-1] + a[i];
          b[++cnt] = sum[i];
        }
        sort(b+1,b+cnt+1);
        int head = 1, tail = cnt;
        LL ans = 0;
        for(int i = 1; i <= m; ++i) {
            int f = b[head++];
            int s = b[tail--];
            if(abs(s-f)-c >= 0) {
                ans += abs(s-f)-c;
            }
            else break;
        }
        printf("%lld\n",ans);
    }
    return 0;
}
E

F:Longest Common Subsequence

  将a数组离散化,枚举三元素,n^3

  求LCS,花费n*3,现在总体复杂度是n^4的

  求LCS这步可以 优化,我们预处理吃nex[i][c],当前i位置后面第一个c在哪里

  就可以在2^3下O(1)求出LCS了

  有个坑的地方就是 a[i]可能会大于m,wa了很久

#include<bits/stdc++.h>
using namespace std;
#pragma comment(linker, "/STACK:102400000,102400000")
#define ls i<<1
#define rs ls | 1
#define mid ((ll+rr)>>1)
#define pii pair<int,int>
#define MP make_pair
typedef long long LL;
const long long INF = 1e18+1LL;
const double Pi = acos(-1.0);
const int N = 2e2+10, M = 1e3+20, mod = 1e9+7,inf = 2e9;


LL n,m,a[N],c,b[N],nex[N][N];
LL v[N];
LL f[N];
LL query(LL x) {
    return lower_bound(b+1,b+c+1,x) - b;
}
int main() {
    while(scanf("%lld%lld",&n,&m)!=EOF) {
        for(int i = 1; i <= n; ++i)
            scanf("%lld",&a[i]),b[i] = a[i];
        sort(b+1,b+n+1);
        c = unique(b+1,b+n+1) - b - 1;
        for(int i = c; i >= 1; --i) {
            if(b[i] > m) c--;
            else break;
        }
        for(int i = 0; i <= 5; ++i) f[i] = 0;
        for(int i = 1; i <= n; ++i) a[i] = query(a[i]);
        memset(nex,0,sizeof(nex));
        memset(v,0,sizeof(v));
        
        for(int i = 0; i <= n; ++i) {
            for(int j = 1; j <= c; ++j) {
                for(int k = i+1; k <= n; ++k) {
                    if(a[k] == j) {
                        nex[i][j] = k;
                        break;
                    }
                }
            }
        }
        
        for(int i = 1; i <= c; ++i) v[i] = 1;
        
        v[c+1] = m - c;
        
        for(int i = 1; i <= c+1; ++i) {
            for(int j = 1; j <= c+1; ++j) {
                for(int k = 1; k <= c+1; ++k) {

                    int fi = 0, se = 0, th = 0;

                    for(int C = 1; C < 8; ++C) {
                        int now = 0;
                        if(C&(4)) {
                            if(!nex[now][i]) {continue;}
                            else now = nex[now][i];
                        }
                        if(C&(2)) {
                            if(!nex[now][j]) {continue;}
                            else now = nex[now][j];
                        }
                        if(C&(1)) {
                            if(!nex[now][k]) {continue;}
                            else now = nex[now][k];
                        }

                        if(C == 7) fi = 1;
                        else if(C == 6 || C == 5 || C == 3) se = 1;
                        else if(C)th = 1;
                        
                    }

                    if(fi){
                        f[3] += v[i]*v[j]*v[k];
                    }
                    else if(se) {
                        f[2] += v[i]*v[j]*v[k];
                    }
                    else if(th) {
                        f[1] += v[i]*v[j]*v[k];
                    }
                    else {
                        f[0] += v[i]*v[j]*v[k];
                    }
                    
                    
                }
            }
        }

        for(int i = 0; i < 3; ++i) cout<<f[i]<<" ";
        cout<<f[3]<<endl;

    }
    return 0;
}
F

 H:Highway

  求一次树的直径

  再从直径的两个端点做一次bfs最短路

#include<bits/stdc++.h>
using namespace std;
#pragma comment(linker, "/STACK:102400000,102400000")
#define ls i<<1
#define rs ls | 1
#define mid ((ll+rr)>>1)
#define pii pair<int,int>
#define MP make_pair
typedef long long LL;
const long long INF = 1e18+1LL;
const double Pi = acos(-1.0);
const int N = 1e5+10, M = 1e3+20, mod = 1e9+7,inf = 2e9;


struct ss{
    int to,next,c;
}e[N * 2];
int head[N],t = 1;
LL sum,mx[N],dp[N];
int from,q[N],vis[N],n;
void add(int u,int v,int w) {
    e[t].to = v;
    e[t].next = head[u];
    e[t].c = w;
    head[u] = t++;
}
void dfs(int u,int f,LL dep) {
    if(dep > sum) {
        sum = dep;
        from = u;
    }
    for(int i = head[u]; i; i = e[i].next) {
        int to = e[i].to;
        if(to == f) continue;
        dfs(to,u,dep + e[i].c);
    }
}
void bfs(int u) {
    int l = 0,r = 1;
    q[++l] = u;
    dp[u] = 0;
    while(l <= r) {
        int k = q[l++];
        for(int i = head[k]; i; i = e[i].next) {
            int to = e[i].to;
            if(vis[to]) continue;
            dp[to] = dp[k] + e[i].c;
            vis[to] = 1;
            q[++r] = to;
        }
    }
    for(int i = 0; i <= n; ++i) vis[i] = 0,mx[i] = max(mx[i],dp[i]);
}
void init() {
    t =1;
    memset(head,0,sizeof(head));
    for(int i  =0; i <= n; ++i) vis[i] = 0,mx[i] = 0;
}
int main() {
    while(scanf("%d",&n)!=EOF) {
        init();
        for(int i = 1; i < n; ++i) {
            int a,b,c;
            scanf("%d%d%d",&a,&b,&c);
            add(a,b,c);
            add(b,a,c);
        }
        sum = 0;
        dfs(1,0,0);
        int fi = from;
        sum = 0;
        dfs(from,0,0);
        LL ans = sum;
        bfs(fi);
        bfs(from);
        for(int i = 1; i <= n; ++i) {
            if(i != fi && i != from) ans += mx[i];
        }
        printf("%lld\n",ans);
    }
    return 0;
}
H

 J:Similar Subsequence

  设 f(i, j, x, y) 表示分别匹配到 ai 和 bj,数字的上界和下界分别是 x 和 y 的方案数。

     注意到 x 和 y 总有一个等于 bj,所以状态数是 nm2 的。

     转移就是枚举 ai+1 匹配的是 bk,要求 bk 落在 [x, y] 中。

     这个可 以用树状数组优化。复杂度是 O(nm2 log m).题解来自icpccamp;

#include<stdio.h>
#include<string.h>
#include<math.h>
#include<iostream>
#include<vector>
#include<queue>
#include<map>
#include<set>
#include<algorithm>
using namespace std;

typedef long long ll;
typedef double db;

const int mod=1000000007;

int t,n,m;
int A[25],B[510];
int dp[25][510][510];
int a[25][510][510];

int lowbit(int x)
{
    return x&(-x);
}

void add(int id,int bd,int x,int v)
{
    while(x)
    {
        a[id][bd][x]+=v;
        if(a[id][bd][x]>=mod) a[id][bd][x]-=mod;
        if(a[id][bd][x]<0) a[id][bd][x]+=mod;
        x-=lowbit(x);
    }
}

int sum(int id,int bd,int x)
{
    int res=0;
    while(x<=m)
    {
        res+=a[id][bd][x];
        if(res>=mod) res-=mod;
        x+=lowbit(x);
    }
    return res;
}

int main()
{
#ifdef Haha
    //freopen("in.in","r",stdin);
#endif // Haha
    while(scanf("%d%d",&n,&m)!=EOF)
    {
        for(int i=1; i<=n; i++) scanf("%d",&A[i]);
        for(int i=1; i<=m; i++) scanf("%d",&B[i]);
        memset(dp,0,sizeof(dp));
        memset(a,0,sizeof(a));
        if(A[1]==0) add(1,m,m,1);
        else add(1,1,m,1);
        for(int i=1; i<=n; i++)
        {
            for(int j=1; j<=m; j++)
            {
                for(int k=1; k<=m; k++)
                {
                    dp[i][j][k]=sum(i,k,B[j]);
                    //printf("%d %d %d %d\n",i,j,k,dp[i][j][k]);
                }
                if(i==1) continue;
                for(int k=1; k<=m; k++)
                {
                    if(dp[i-1][j][k]==0) continue;
                    int L,R;
                    if(A[i-1]==0) L=B[j],R=k;
                    else L=k,R=B[j];
                    if(L>R) continue;
                    
                    if(A[i]==0)
                    {
                        add(i,R,R,dp[i-1][j][k]);
                        add(i,R,L-1,-dp[i-1][j][k]);
                    }
                    else
                    {
                        add(i,L,R,dp[i-1][j][k]);
                        add(i,L,L-1,-dp[i-1][j][k]);
                    }
                }
            }
        }
        int ans=0;
        for(int i=1; i<=m; i++)
        {
            for(int j=1; j<=m; j++)
            {
                ans+=dp[n][i][j];
                if(ans>=mod) ans-=mod;
            }
        }
        printf("%d\n",ans);
    }
    return 0;
}
J

 

posted @ 2017-05-15 21:28  meekyan  阅读(322)  评论(0编辑  收藏  举报