ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

2020 CCPC-Wannafly Winter Camp Day2

2020-01-13 23:56:15  阅读:513  来源: 互联网

标签:tmp head Winter val int res ll Camp Day2


2020 CCPC-Wannafly Winter Camp Day2

A 托米的字符串

虽然每个子串出现的概率是相同的,但是同一长度的子串个数是不同的,所以要分别处理。计算出某一长度的情况下,元音字母的贡献,然后计算期望即可。

cls题解上的思路很清晰...我的代码太暴力了。

const int N = 1000010;
char s[N];
int a[N],n;
ll d[N],c[N];
int main()
{
    scanf("%s",s+1);
    n = strlen(s+1);
    double res = 0;
    for(int i=1;i<=n;i++){
        if(s[i] == 'a' || s[i] == 'e' || s[i] == 'i' || s[i] == 'o' || s[i] == 'u' || s[i] == 'y'){
            a[i] = 1;
        }
    }
    for(int i=1;i<=n;i++){
        if(a[i] == 1){
            d[i] = min(i,n-i+1);
        }
        d[i] += d[i-1];
        a[i] += a[i-1];
    }
    for(int i=1;i<=n;i++){
        int l = min(i,n-i+1);
        int r = max(i,n-i+1);
        c[i] = 1ll * min(l,r) * (a[r] - a[l-1]) + d[l-1] + d[n] - d[r];//长度为i的贡献
        //cout << i << ' ' <<' ' << l << ' ' << r << ' ' << c[i] << endl;
        res += 1.0 * c[i] / i;
    }
    res /= 1ll*n*(n+1)/2;
    printf("%.10f\n",res);
    return 0;
}

C.纳新一百的石子游戏

nim游戏,再胜局的情况下,要使得异或和变为0,必须选取某一堆拿一定数量的石子。如果逐个遍历前面所有的石子去验证是否可行复杂度会爆炸,所以通过位运算的规律来优化。异或和的结果最高位的1可以在异或操作中起到翻转作用,所以只需要一个长度60的数组来记录对应位为1的数字有多少个就可以了。

const int N = 100010;
int d[61],n;
ll a[N];
int main()
{
    scanf("%d",&n);
    for(int i=1;i<=n;i++){
        scanf("%lld",&a[i]);
    }
    ll x = 0;
    for(int i=1;i<=n;i++){
        for(int j=60;j>=0;j--){
            if(a[i] >> j & 1){
                d[j]++;
            }
        }
        x ^= a[i];
        int res = 0;
        for(int j=60;j>=0;j--){
            if(x >> j & 1){
                res = d[j];
                //printf("%d\n",d[j]);
                break;
            }
        }
        printf("%d\n",res);
    }
    return 0;
}

E. 阔力梯的树

考虑子树合并的操作,每次都让轻儿子向重儿子合并即可。方法是重儿子的所有数存在set中,然后将所有轻儿子的节点以\(O(logSize)\)的复杂度插入,插入的时候顺便更新答案即可。

有关树上启发式合并的内容:https://oi-wiki.org/graph/dsu-on-tree/

const int N = 100010;
int head[N],ver[N<<1],nxt[N<<1],tot,n,cnt,id[N],l[N];
int son[N],sz[N];
ll res[N];
set<int> s;
void add(int x,int y){
    ver[++tot] = y;nxt[tot] = head[x];head[x] = tot;
}
void pre(int x){
    sz[x] = 1;
    l[x] = ++ cnt;
    id[cnt] = x;
    for(int i=head[x];i;i=nxt[i]){
        int y = ver[i];
        pre(y);
        sz[x] += sz[y];
        if(sz[y] > sz[son[x]]){
            son[x] = y;
        }
    }
}
void modify(int x,int val){
    set<int>::iterator it = s.lower_bound(val);
    if(s.size() == 0){
        s.insert(val);
        return;
    }
    if(it == s.begin()){ // 最小的比它大
        ll tmp = (*it) - val;
        res[x] += tmp * tmp;
    }else if(it == s.end()){
        it--;
        ll tmp = val - (*it);
        res[x] += tmp * tmp;
    }else{
        ll tmp = (*it) - (*(--it));
        res[x] -= tmp * tmp;
        tmp = val - (*it);
        res[x] += tmp * tmp;
        tmp = (*(++it)) - val;
        res[x] += tmp * tmp;
    }
    s.insert(val);
}
void dfs(int x,bool flag){
    for(int i=head[x];i;i=nxt[i]){
        int y = ver[i];
        if(y == son[x])continue;
        dfs(y,false);
    }
    if(son[x])dfs(son[x],true);
    res[x] = res[son[x]];
    for(int i=head[x];i;i=nxt[i]){
        int y = ver[i];
        if(y == son[x])continue;
        //cout << y << ' ' << l[y] << ' ' << l[y] + sz[y] - 1 << endl;
        for(int j=l[y];j<=l[y]+sz[y]-1;j++){
            //添加,计算答案
            modify(x,id[j]);
        }
    }
    modify(x,x);
    if(!flag){
        s.clear();
    }
}
int main()
{
    scanf("%d",&n);
    for(int i=2;i<=n;i++){
        int x;
        scanf("%d",&x);
        add(x,i);
    }
    pre(1);
    dfs(1,false);
    for(int i=1;i<=n;i++){
        printf("%lld\n",res[i]);
    }
    return 0;
}

H. 叁佰爱抠的序列

欧拉回路问题,m个点,如果m是奇数那么完全图即欧拉图,是偶数则需要至少补\((m-2)\over 2\)条边使得m-2个点的度数为偶数,2个点度数为奇数并作为起始点和终点。

二分找到最大的m,然后建图求出欧拉路径即可

const int N = 2010;
const int M = 8000010;
ll n;
int head[N],ver[M],nxt[M],tot;
int st[N*N],ans[N*N],vis[M],top,t;

inline ll getNum(ll x){
    if(x & 1){
        return (x * x - x) / 2 + 1;
    }else return x * x / 2;
}
inline void add(int x,int y){
    ver[++tot] = y;nxt[tot] = head[x];head[x] = tot;
}
void euler(){
    st[++top] = 1;
    while(top){
        int x = st[top],i = head[x];
        while(i && vis[i]) i = nxt[i];
        if(i){
            st[++top] = ver[i];
            vis[i] = vis[i^1] = true;
            head[x] = nxt[i];
        }else{
            top --;
            ans[++t] = x;
        }
    }
}
int main()
{
    scanf("%lld",&n);
    ll m = 0,l = 1,r = 1500000000;
    while(l < r){
        ll mid = l + r + 1>> 1;
        if(getNum(mid) <= n){
            l = mid;
        }else r = mid - 1;
    }
    m = l;
    if(n > 2000000){
        printf("%lld\n",m);
        return 0;
    }
    tot = 1;
    for(int i=1;i<=m;i++){
        for(int j=i+1;j<=m;j++){
            add(i,j);
            add(j,i);
        }
    }
    if(m % 2 == 0){
        for(int i = 2;i < m;i += 2){
            add(i,i+1);
            add(i+1,i);
        }
    }
    euler();
   // cout << t << endl;
    for(int i=t+1;i<=n;i++){
        ans[i] = 1;
    }
    printf("%lld\n",m);
    for(int i=1;i<=n;i++){
        if(i > 1)printf(" ");
        printf("%d",ans[i]);
    }
    puts("");
    return 0;
}

K.破忒头的匿名信

所有的串总长为5e5,那么不同长度的串最多有根号n个。建好AC自动机后,顺着遍历目标串,对于每个符合要求的当前后缀,都可以产生一次有效转移(所有转移等同于DAG上求最短路),总共最多发生\(\sqrt{n}\)次转移。所以复杂度最多\(O(n*\sqrt{n})\)。

const int inf = 0x3f3f3f3f;
const int N = 5e5 + 10;
int n,vis[N];
char s[N];
ll d[N];
namespace AC{
    int tr[N][26],tot;
    int e[N],fail[N],dep[N];
    ll val[N];
    queue<int> q;
    void init(){
        for(int i=0;i<=tot;i++){
            memset(tr[i],0,sizeof tr[i]);
            fail[i] = e[i] = 0;
        }
        tot = 0;
    }
    void insert(char *s,ll v){
        int u = 0;
        int len = strlen(s + 1);
        for(int i=1;i<=len;i++){
            if(!tr[u][s[i] - 'a']){
                tr[u][s[i] - 'a'] = ++tot;
                val[tot] = inf;
            }
            u = tr[u][s[i] - 'a'];
            dep[u] = i;
        }
        e[u] ++;
        val[u] = min(val[u],v);
    }
    void build(){
        for(int i=0;i<26;i++)if(tr[0][i])q.push(tr[0][i]);
        while(q.size()){
            int u = q.front();q.pop();
            for(int i=0;i<26;i++){
                if(tr[u][i])fail[tr[u][i]] = tr[fail[u]][i],q.push(tr[u][i]);
                else tr[u][i] = tr[fail[u]][i];
            }
        }
    }
    void query(char *t){
        int u = 0,res = 0;
        for(int i=1;t[i];i++){
            u = tr[u][t[i] - 'a'];
            for(int j = u; j; j = fail[j]){ //深度 dep[j], 价值 val[j];
                if(vis[i - dep[j]] && e[j]){
                    d[i] = min(d[i],d[i-dep[j]] + val[j]);
                    vis[i] = 1;
                }
            }
        }
    }
}
int main(){
    scanf("%d",&n);
    AC::init();
    for(int i=1;i<=n;i++){
        ll val;
        scanf("%s%lld",s+1,&val);
        AC::insert(s,val);
    }
    scanf("%s",s+1);
    AC::build();
    int len = strlen(s+1);
    vis[0] = 1;
    for(int i=1;i<=len;i++){
        d[i] = 1ll * inf * inf;
    }
    AC::query(s);
    //for(int i=1;i<=len;i++)cout << d[i] << ' ' ; cout << endl;
    if(!vis[len]){
        puts("-1"); 
    }else{
        printf("%lld\n",d[len]);
    }
    return 0;
}

标签:tmp,head,Winter,val,int,res,ll,Camp,Day2
来源: https://www.cnblogs.com/1625--H/p/12189988.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有