暑期集训 Contest 1

Glory and LCS

时间限制: 1 Sec  内存限制:128 MB
提交: 217  解决: 48

题目描述

大家都知道,Glory不但知识水平高,并且非常喜欢思考,有一天Glory在思考一个问题,他在纸上写了两个1到n的排列,并且他想知道这两个排列的最大公共子序列的长度是多少,当然像Glory这么优秀的人当然一眼就看出了这个题目的答案,但是他太忙了,不想打这个代码,于是他扔给了他的小弟,但是他的小弟知识水平不够,所以他想找你萌帮帮他,你萌能帮他解决这个问题吗。

输入

第一行一个数T,表示数据的测试组数(T<=5)

每组数据一个n,表示排列的长度(1<= n <= 1e5)

接下来两行,每行一个1~n的排列

输出

对于每组数据,输出一个数表示最长公共子序列的长度。

样例输入

2
2
1 2
1 2
3
1 3 2
2 3 1

样例输出

2
1

 

由于是排列所以每个元素只出现一次。我们可以记录下来每个数 p 在第一个排列中出现的位置a[p] = i,在读第二个数列的时候把第二个排列中每个数 p 在第一个排列中出现的位置依次存在 b[] 中,即b[i] = a[p]。则 b[](位置序号)中的上升子序列对应的元素序列均为第一个排列的子序列,求 b[] 的最长上升子序列即可。

代码:

#include
#include
#include
usingnamespace std;
const int maxn = 1e5 + 5;
int a[maxn],b[maxn],c[maxn];
int main()
{
    int t,n,p;
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d",&n);
        for(int i = 1;i <= n; ++i)
        {
            scanf("%d",&p);
            a[p] = i;
        }
        for(int i = 1;i <= n; ++i)
        {
            scanf("%d",&p);
            b[i] = a[p];
        }
        int len = 1,j;
        c[0] = 0;
        for(int i = 1;i <= n; ++i)
        {
            j = lower_bound(c,c + len,b[i]) - c;

            if(j == len) ++len;

            c[j] = b[i];
        }
        printf("%d\n",len - 1);
    }
    return 0;
}

Godv的数列

时间限制: 3 Sec  内存限制: 128 MB
提交: 235  解决: 20

题目描述

Godv拿到了一个长度为n(1<=n<=1e5)的数列,数列中每个数ai都满足1<=ai<=1e9。

然后神奇的Godv对这个数列施加了魔法。“巴拉拉能量~~~~哈!~~”

 暑期集训 Contest 1_第1张图片

数列在Godv的魔法的影响下,发生了如下的变化:

首先,对相邻数字两两相加,得到一个长为n-1的新数列a’,用伪代码表示如下

for i=1:n-1

 a'[i]=a[i]+a[i+1]

用a'代替a

重复进行这样的操作,直到数列长度为1

现在聪明的Godv想考考你,最后剩下的数的大小是多少?由于Godv不喜欢大数,所以请将结果对1001取模后输出

输入

多组数据,第一行为数据组数T(1<=T<=25)。每组数据第一行包含一个数n。第二行为这个数列,每两个数之间用空格隔开

输出

每组数据输出一个数,即最后剩下的数。

样例输入

21121 2

样例输出

13

提示

假设 n=3,初始数列为1 2 3

那么一次变化后,数列变成 3 5  (1+2=3,2+3=5)

再变一次后,变成8 (3+5=8)

ans=8%1001=8

推几次就可以发现(比赛的时候就没发现)结果为:

C(n - 1,0)* a0 + C(n - 1,1)* a1 + … + C(n - 1,n - 1)an-1

由于模数 1001 不是素数,需要用拓展 Lucas 求组合数,简单点就是把 1001 分解质因数,分别求了再用中国剩余定理合起来。

#include
#include
#include
#define ll long long
using namespace std;
const ll lcm = 1001;
const ll mod[3] = {7,11,13};
ll a[3];
ll Fastpow(ll a,ll b,ll mo)
{
    ll ans = 1;
    while(b > 0)
    {
        if(b & 1) ans = (ans * a) % mo;
        b >>= 1;
        a = (a * a) % mo;
    }
    return ans;
}
ll Getc(ll a,ll b,ll mo)
{
    if(a < b)return 0;
    if(b > a - b) b = a - b;
    ll s1 = 1,s2 = 1;
    for(ll i = 0;i < b; ++i)
    {
        s1 = s1 * (a - i) % mo;
        s2 = s2 * (i + 1) % mo;
    }
    return s1 * Fastpow(s2,mo - 2,mo) % mo;
}
ll Lucas(ll n,ll k,ll mo)
{
    if(k == 0)return 1;
    return Getc(n % mo,k % mo,mo) * Lucas(n / mo,k / mo,mo) % mo;
}
ll Exgcd(ll a,ll b,ll &x,ll &y)
{
    if(b == 0) x = 1,y = 0;
    else
    {
        Exgcd(b,a % b,y,x);
        y -= x * (a / b);
    }
}
ll Calc(ll x,ll y)
{
    ll ans = 0,M,m,temp;
    for(inti = 0;i < 3; ++i)
    {
        temp = Lucas(x,y,mod[i]);
        Exgcd(lcm / mod[i],mod[i],M,m);
        ans = (ans + temp * M * (lcm / mod[i])) % lcm;
    }
    return ans;
}
int main()
{
    ll t,n,temp;
    scanf("%lld",&t);
    while(t--)
    {
        ll ans = 0;
        scanf("%lld",&n);
        for(ll i = 0;i < n; ++i)
        {
            scanf("%lld",&temp);
            ans = (ans + Calc(n - 1,i) * temp) % lcm;
        }
        printf("%lld\n",ans);
    }
}

子树第K小

时间限制: 4 Sec  内存限制: 256 MB
提交: 68  解决: 11

题目描述

暑期集训 Contest 1_第2张图片

输入

暑期集训 Contest 1_第3张图片

输出

样例输入

5
1 2 3 4 5
1 2
1 3
3 4
3 5
5
1 3
1 4
3 1
3 3
2 1

样例输出

3
4
3
5
2

 

主席树的模板题,不过这道不是直接求区间第 k 小,需要做一些处理。问的是以 x 为根的子树中的第 k 小。可以先将这棵树的 DFS 序用数组 po[] 存下来。对于一棵有根树,一棵子树的所有结点的 DFS 序在 po[] 中是一段连续的区间,对于每个点我们可以记录下来以它为根的子树中节点个数 sum[x],则每次查询 po[x] ~ (po[x]  + sum[x] - 1) 中的第 k 小即可。P.S 主席树真是个神奇的数据结构。

#include 
#include 
#include 
#include 
#include 
using namespace std;
const int MAXN = 100000 + 5;
const int M = MAXN * 30;
int n,q,m,tot;
int a[MAXN], t[MAXN];
int T[M], lson[M], rson[M],c[M];

void Init_hash()
{
    for(inti = 1; i <= n;i++) t[i] = a[i];
    sort(t+1,t+1+n);
    m = unique(t+1,t+1+n)-t-1;
}
int build(int l,intr)
{
    introot = tot++;
    c[root] = 0;
    if(l != r)
    {
        intmid = (l+r)>>1;
        lson[root] = build(l,mid);
        rson[root] = build(mid+1,r);
    }
    return root;
}
int Hash(int x)
{
    return lower_bound(t+1,t+1+m,x) - t;
}
int update(int root,intpos,int val)
{
    intnewroot = tot++, tmp = newroot;
    c[newroot] = c[root] + val;
    intl = 1, r = m;
    while(l < r)
    {
        intmid = (l+r)>>1;
        if(pos <= mid)
        {
            lson[newroot] = tot++; rson[newroot] = rson[root];
            newroot = lson[newroot]; root = lson[root];
            r = mid;
        }
        else
        {
            rson[newroot] = tot++; lson[newroot] = lson[root];
            newroot = rson[newroot]; root = rson[root];
            l = mid+1;
        }
        c[newroot] = c[root] + val;
    }
    return tmp;
}
int query(int left_root,intright_root,int k)
{
    intl = 1, r = m;
    while( l < r)
    {
        intmid = (l+r)>>1;
        if(c[lson[left_root]]-c[lson[right_root]] >= k )
        {
            r = mid;
            left_root = lson[left_root];
            right_root = lson[right_root];
        }
        else
        {
            l = mid + 1;
            k -= c[lson[left_root]] - c[lson[right_root]];
            left_root = rson[left_root];
            right_root = rson[right_root];
        }
    }
    return l;
}

int cal;
int dfs[MAXN],po[MAXN],b[MAXN],sum[MAXN];
bool vis[MAXN];
vector g[MAXN];
int DFS(int x)
{
    sum[x]++;
    intlen = g[x].size();
    for(inti = 0;i < len; ++i)
    {
        intu = g[x][i];
        if(!vis[u])
        {
            vis[u] =true;
            po[u] = cal,b[cal] = a[u],++cal;
            sum[x] += DFS(u);
        }
    }
    return sum[x];
}
int main()
{
    while(scanf("%d",&n) != EOF)
    {
        tot = 0;
        for(inti = 0;i <= n; ++i) g[i].clear();
        memset(vis,false,sizeof(vis));
        memset(sum,0,sizeof(sum));
        for(inti = 1;i <= n;i++) scanf("%d",&a[i]);
        intx,y;
        for(inti = 1;i < n; ++i)
        {
            scanf("%d %d",&x,&y);
            g[x].push_back(y);
            g[y].push_back(x);
        }
        cal = 2;
        po[1] = 1,b[1] = a[1],vis[1] = true;
        DFS(1);
        Init_hash();
        T[n+1] = build(1,m);
        for(inti = n;i ;i--)
        {
            intpos = Hash(b[i]);
            T[i] = update(T[i+1],pos,1);
        }
        scanf("%d",&q);
        while(q--)
        {
            intl,r,k,now;
            scanf("%d %d",&now,&k);
            l = po[now];
            r = l + sum[now] - 1;
            printf("%d\n",t[query(T[l],T[r+1],k)]);
        }
    }
    return 0;
}

 

你可能感兴趣的:(基础算法)