2019 杭电多校(第二场)

1005 Everything Is Generated In Equal Probability (数学)

http://acm.hdu.edu.cn/showproblem.php?pid=6595

题意

期望

给你一个N 问在1-N随机选择一个数,随机排列1-n 求逆序对,然后随机选择子序列 在求逆序对,直到数列长度为0 问逆序对的期望个数

思路

n个数全排列的逆序对期望个数为 (n*(n-1))/4  一共有n*(n-1)/2 是逆序对的期望为1/2 

dp[i]为数组长度为i的后继期望 

dp[i] = (n*(n-1))/4 + dp[i]*C[0][n]/pow(2,n) + ∑dp[i]*C[i][n]/pow(2,n)

dp[i] = (n(n-1)/4 + ∑dp[i]*C[i][n]/pow(2,n)) * pow(2,n) / (pow(2,n)-1;

对于N 计算dp 1-n的和 除以N

代码

#include<bits/stdc++.h>

using namespace std;

typedef long long ll;
const ll mod = 998244353;
ll C[3300][3300];
ll dp[3300];
ll q[3300];
ll qw[3300];
ll qw2[3300];
ll qsort(ll x,ll n)
{
    ll ans = 1;
    while(n)
    {
        if(n % 2 == 1)
        {
            ans = (ans * x) % mod;
        }
        x = (x * x) % mod;
        n /= 2;
    }
    ans %= mod;
    return ans;
}

void ok()
{
    ll xx = 1;
    for(ll i = 1;i <= 3000;i++)
    {
        xx *= 2;
        xx %= mod;
        q[i] = xx;
        qw[i] = qsort(xx,mod-2);
        qw2[i] = qsort(xx-1,mod-2);
    }
    dp[0] = 0;
    dp[1] = 0;
    ll qwe = qsort(4,mod-2);
    for(ll i = 2;i <= 3000;i++)
    {
        dp[i] = (i*(i-1)*qwe)%mod;
        for(ll j = 1;j < i;j++)
        {
            dp[i] = (dp[i] + ((C[i][j]*dp[j])%mod)*qw[i])%mod;
        }
        dp[i] = ((dp[i]*q[i])%mod*(qw2[i]))%mod;
    }
}
 void cc(ll n)
 {
     for(ll i=0;i<=n;i++)
       C[i][0]=1;
     for(ll i=1;i<=n;i++)
     {
         for(ll j=1;j<=i;j++)
         C[i][j]=(C[i-1][j-1]+C[i-1][j])%mod;
     }
 }
int main()
{
    ll n;
    cc(3002);
    ok();
    while(scanf("%lld",&n)!= EOF)
    {
        ll ans = 0;
        for(ll i = 2;i <= n;i++)
        {
            ans = (ans + dp[i]) % mod;
        }
        ans = (ans * qsort(n,mod-2))%mod;
        printf("%lld\n",ans);
    }
    return 0;
}

1009 I Love Palindrome String (回文树)

http://acm.hdu.edu.cn/showproblem.php?pid=6599

题意

回文树

给你一个长度为n的字符串

为本身是回文串 前一半也是回文串的子串个数

思路

前一半是回文串 那么后一半也一定是回文串

回文树的fail指向以当前结尾的最长回文串,如何一个回文串的fail指针指向的回文串长度或继续向前 长度存在他的一半 那么他就是符合要求的回文串

递归找长度一半会超时 可以按fail指针方向边建一个树 跑DFS

代码

#include <bits/stdc++.h>

using namespace std;

const int MAXN = 310005 ;
const int N = 26 ;

struct Palindromic_Tree {
    int next[MAXN][N] ;//next指针,next指针和字典树类似,指向的串为当前串两端加上同一个字符构成
    int fail[MAXN] ;//fail指针,失配后跳转到fail指针指向的节点
    long long cnt[MAXN] ;
    //cnt[i]表示节点i表示的本质不同的串的个数(建树时求出的不是完全的,最后count()函数跑一遍以后才是正确的)
    int num[MAXN] ; //num[i]表示以节点i表示的最长回文串的最右端点为回文串结尾的回文串个数
    int len[MAXN] ;//len[i]表示节点i表示的回文串的长度
    int S[MAXN] ;//存放添加的字符
    int last ;//指向上一个字符所在的节点,方便下一次add
    int n ;//字符数组指针
    int p ;//节点指针

    vector<int> to[MAXN]; //失配指针反向边

    int newnode ( int l ) {//新建节点
        for ( int i = 0 ; i < N ; ++ i ) next[p][i] = 0 ;
        cnt[p] = 0 ;
        num[p] = 0 ;
        len[p] = l ;
        return p ++ ;
    }

    void init () {//初始化
        p = 0 ;
        newnode (0) ;
        newnode (-1) ;
        last = 0 ;
        n = 0 ;
        S[n] = -1 ;//开头放一个字符集中没有的字符,减少特判
        fail[0] = 1 ;
        to[1].push_back(0);
    }

    int get_fail ( int x ) {//和KMP一样,失配后找一个尽量最长的
        while ( S[n - len[x] - 1] != S[n] ) x = fail[x] ;
        return x ;
    }

    void add ( int c ) {
        c -= 'a';
        S[++ n] = c ;
    //  cout<<n<<" "<<(char)(S[n]+'a')<<endl;
        int cur = get_fail ( last ) ;//通过上一个回文串找这个回文串的匹配位置
        if ( !next[cur][c] ) {//如果这个回文串没有出现过,说明出现了一个新的本质不同的回文串
            int now = newnode ( len[cur] + 2 ) ;//新建节点
            fail[now] = next[get_fail ( fail[cur] )][c] ;//和AC自动机一样建立fail指针,以便失配后跳转

            to[next[get_fail ( fail[cur] )][c]].push_back(now);

            next[cur][c] = now ;
            num[now] = num[fail[now]] + 1 ;
        }
        last = next[cur][c] ;
        cnt[last] ++ ;
    }

    void count () {
        for ( int i = p - 1 ; i >= 0 ; -- i ) cnt[fail[i]] += cnt[i] ;
        //父亲累加儿子的cnt,因为如果fail[v]=u,则u一定是v的子回文串!
    }
} ;
Palindromic_Tree A;
char s[MAXN];
int vis[MAXN],ans[MAXN];
void dfs(int u)
{
    if(vis[(A.len[u]+1) / 2] == 1) ans[A.len[u]] += A.cnt[u];
    if(A.len[u] >= 0) vis[A.len[u]] = 1;
    for(int i = 0;i < A.to[u].size();i++)
    {
        int v = A.to[u][i];
        dfs(v);
    }
    if(A.len[u] >= 0) vis[A.len[u]] = 0;
}
int main()
{
    while(scanf("%s",s ) != EOF)
    {
        int n = strlen(s);
        for(int i = 0;i <= n;i++)
        {
            A.to[i].clear();
        }
        memset(ans,0,sizeof(ans));
        A.init();
        for(int i =0;i < n;i++)
        {
            A.add(s[i]);
        }
        A.count();
        dfs(1);
        ans[1] = n;
        for(int i = 1;i <= n;i++)
        {
            if(i!= 1) printf(" ");
            printf("%d",ans[i]);
        }
        printf("\n");
    }
}

1010 Just Skip The Problem (思维)

http://acm.hdu.edu.cn/showproblem.php?pid=6600

题意

给你一个数n 你可以进行若干次询问 每次询问你给出一个数m 他会告诉你n^m 是否等于m 

问最优解的情况下 询问的方案数

思路

最优解就是依次询问每一位 方案数为n!膜数是1e6+3 那么大于1e6+3的树为0

代码

#include<bits/stdc++.h>

#define ll long long
#define mod 1000003
#define inf 0x3f3f3f3f
using namespace std;

int main()
{
    ll n;
    while(~scanf("%lld",&n))
    {
        ll ans=1;
        if(n>=mod)
        {
            printf("0\n");
            continue;
        }
        for(ll i=1; i<=n; i++)
            ans=(ans*i)%mod;
        printf("%lld\n",ans);
    }
    return 0;
}

1011 Keen On Everything But Triangle (主席树)

http://acm.hdu.edu.cn/showproblem.php?pid=6601

题意

给你n个数 m次询问 每次问区间l-r之间能组成最大三角形面积

思路

最不成三角形最优情况即斐波那契数列,可知区间长度大于40 一定有解

问题即求区间第k大 sort肯定超时 可以用主席树

代码

#include<bits/stdc++.h>
#include <cstdio>
#define ll long long
#include <vector>
#include <algorithm>
using namespace std;

const ll MAX = 112345;

struct Node
{
    ll sum, l, r;
} tree[MAX * 40];

ll root[MAX], cnt;
ll data[MAX];
vector<ll> sorted;

//离散化获得ID
ll get_id(ll x)
{
    return lower_bound(sorted.begin(), sorted.end(), x) - sorted.begin() + 1;
}

void init()
{
    cnt = 0;
    root[0] = 0;
}

//根据旧版本的线段树创建新线段树的节点
ll create_node(ll po)
{
    ll idx = ++cnt;
    tree[idx].sum = tree[po].sum + 1;
    tree[idx].l = tree[po].l;
    tree[idx].r = tree[po].r;
    return idx;
}

void updata(ll &o, ll po, ll l, ll r, ll pos)
{
    o = create_node(po);
    if (l == r) return;
    ll m = (l + r) >> 1;
    if (pos <= m) updata(tree[o].l, tree[po].l, l, m, pos);
    else updata(tree[o].r, tree[po].r, m + 1, r, pos);
}

//二分查询
ll query(ll s, ll e, ll l, ll r, ll k)
{
    if (l == r) return l;
    ll m = (l + r) >> 1;
    ll sum = tree[tree[e].l].sum - tree[tree[s].l].sum;
    if (k <= sum) return query(tree[s].l, tree[e].l, l, m, k);
    else return query(tree[s].r, tree[e].r, m + 1, r, k - sum);
}

int main()
{
    ll n, m;
    while (~scanf("%lld %lld", &n, &m))
    {
        init();
        for (ll i = 1; i <= n; i++)
        {
            scanf("%lld", &data[i]);
            sorted.push_back(data[i]);
        }
        sort(sorted.begin(), sorted.end());
        sorted.erase(unique(sorted.begin(), sorted.end()), sorted.end());
        ll num = sorted.size();
        for (ll i = 1; i <= n; i++)
            updata(root[i], root[i - 1], 1, num, get_id(data[i]));
        for(ll i=0; i<m; i++)
        {
            ll l,r;
            scanf("%lld%lld",&l,&r);
            ll ans=-1;
            for(ll k=1; k<=r-l-1; k++)
            {
                ll a,b,c;
                c=sorted[query(root[l - 1], root[r], 1, num, r-l+2-k) - 1];
                b=sorted[query(root[l - 1], root[r], 1, num, r-l+1-k) - 1];
                a=sorted[query(root[l - 1], root[r], 1, num, r-l+0-k) - 1];
                if(a+b>c)
                {
                    ans=a+b+c;
                    break;
                }
            }
            printf("%lld\n",ans);
        }
    }
    return 0;
}

1012 Longest Subarray (线段树)

http://acm.hdu.edu.cn/showproblem.php?pid=6602

题意

给你c k 和n个数 求满足条件的最长区间长度 

条件  每个数的个数>= k或者为0

思路

枚举每个右端点 求每个左端点1-c中满足条件的个数是多少 找最左端为c的点

代码 

#include <bits/stdc++.h>
using namespace std;
const int MAXN = 100005;
struct node
{
    int data,lazy;
}tree[MAXN*4];
int a[MAXN];
int n,c,k;
vector<int> q[MAXN];
int maxn,qw;
void build(int x,int l,int r)
{
    tree[x].data = 0;
    tree[x].lazy = 0;
    if(l==r) return ;
    int mid = (l + r) / 2;
    build(x*2,l,mid);
    build(x*2+1,mid+1,r);
}
void pushdown(int rt)
{
    if(tree[rt].lazy)
    {
        tree[rt*2].lazy += tree[rt].lazy;
        tree[rt*2+1].lazy += tree[rt].lazy;
        tree[rt*2].data += tree[rt].lazy;
        tree[rt*2+1].data += tree[rt].lazy;
        tree[rt].lazy = 0;
    }
}
void updata(int l,int r,int rt,int L,int R,int x)
{
    if(l > r) return ;
    if(l == L&&r == R)
    {
        tree[rt].data += x;
        tree[rt].lazy += x;
        return ;
    }
    pushdown(rt);
    int mid = (L + R) / 2;
    if(mid >= r)
    {
        updata(l,r,rt*2,L,mid,x);
        tree[rt].data = max(tree[rt*2].data,tree[rt*2+1].data);
    }
    else if(mid < l)
    {
        updata(l,r,rt*2+1,mid+1,R,x);
        tree[rt].data = max(tree[rt*2].data,tree[rt*2+1].data);
    }
    else
    {
        updata(l,mid,rt*2,L,mid,x);
        updata(mid+1,r,rt*2+1,mid+1,R,x);
        tree[rt].data = max(tree[rt*2].data,tree[rt*2+1].data);
    }
}

void query(int l,int r,int rt,int L,int R)
{
    if(L==R)
    {
        if(tree[rt].data == c) qw = L;
        return ;
    }
    pushdown(rt);
    int mid = (L + R ) / 2;
    if(mid >= r)
    {
        if(tree[rt*2].data >= c) query(l,mid,rt*2,L,mid);
    }
    else if(mid < l)
    {
        if(tree[rt*2+1].data >= c) query(l,mid,rt*2+1,mid+1,R);
    }
    else
    {
        if(tree[rt*2].data >= c) query(l,mid,rt*2,L,mid);
        else if(tree[rt*2+1].data >= c) query(mid+1,r,rt*2+1,mid+1,R);
    }
}
int main()
{
//    freopen("in.txt","r",stdin);

    while(scanf("%d%d%d",&n,&c,&k) != EOF)
    {
        for(int i = 1;i <= n;i++)
        {
            scanf("%d",&a[i]);
        }
        for(int i = 1;i <= c;i++)
        {
            q[i].clear();
            q[i].push_back(0);
        }
        int ans=0;
        build(1,1,n);
        for(int i = 1;i <= n;i++)
        {
            int x = a[i];
            q[x].push_back(i);
            int siz = q[x].size();
            if(siz > k)
            {
                int l = q[x][siz-k-1]+1,r = q[x][siz-k];

                updata(l,r,1,1,n,1);
            }
            int l = q[x][siz-2]+1,r = i-1;

            updata(l,r,1,1,n,-1);

            updata(i,i,1,1,n,c-1);

            qw = 0;
            query(1,i,1,1,n);
            if(qw != 0)
            {
                ans = max(i-qw+1,ans);
            }

        }
        printf("%d\n",ans);
    }
    return 0;
}

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值