ZF_20160704_CF15X

246E
树上每个节点对应一个字符串,指定子树和深度,求不同字符串个数。
STL解决。

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<map>
#include<set>
#include<vector>
#include<utility>
#include<string>
using namespace std;


const int _=200010;
int n,m;
char c[_][33];

namespace G
{
    int dep[_],dfn[_],lea[_],step;
    vector<int>V[_];
    vector<pair<int,int> >Pt[_];
    map<pair<int,int>,int>M;
    set<string>S;
    void dfs(int u,int f,int d)
    {
        dfn[u]=++step;
        Pt[d].push_back(make_pair(step,u));
        dep[u]=d;
        int len=V[u].size();
        for(int i=0;i<len;i++)
        {
            int v=V[u][i];
            dfs(v,u,d+1);
        }
        lea[u]=++step;
    }
    int get(int v,int k)
    {
        if(M[make_pair(v,k)])return M[make_pair(v,k)]-1;
        S.clear();
        vector<pair<int,int> >::iterator
        l=lower_bound(Pt[dep[v]+k].begin(),Pt[dep[v]+k].end(),make_pair(dfn[v],_)),
        r=lower_bound(Pt[dep[v]+k].begin(),Pt[dep[v]+k].end(),make_pair(lea[v],_));
        for(vector<pair<int,int> >::iterator ir=l;ir!=r;ir++)
            S.insert(string(c[ir->second]+1));
        return (M[make_pair(v,k)]=S.size()+1)-1;
    }
    int Go()
    {
        while(~scanf("%d",&n))
        {
            for(int i=0;i<=n;i++)V[i].clear(),Pt[i].clear();
            M.clear();S.clear();
            for(int i=1;i<=n;i++)
            {
                int x;
                scanf("%s%d",c[i]+1,&x);
                V[x].push_back(i);
            }
            step=0;
            dfs(0,-1,1);
            scanf("%d",&m);
            while(m--)
            {
                int v,k;
                scanf("%d%d",&v,&k);
                printf("%d\n",get(v,k));
            }
        }
    }
}
int main()
{
    G::Go();
}

248D
一条街n个点,shop可买一块糖,给每个home送去一块糖,在时间限制t的前提下,求初始时带的糖的最小值。
对答案进行二分。

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int dat[500010],n,m,num[500010],t,last,o;
char c[500010];
bool OK(int mid)
{
    int tmp=1e9,res=0;
    num[0]=mid;
    m=last;//最后一个 home
    for(int i=1;i<=n;++i)
    {
        num[i]=num[i-1]+dat[i];
        if(num[i]==0 && num[i-1]==-1)m=max(m,i);
    }
    if(m==0)return 1;//没有home
    for(int i=1;i<=m;++i)
    {
        res++;
        if(num[i-1]==0 && num[i]==-1)
        {
            o=i;
            tmp=min(tmp,res+(m-i)*2);
        }
        if(num[i-1]==-1 && num[i]==0)
        {
            res+=(i-o)*2;
        }
    }
    tmp=min(tmp,res);
    return tmp<=t;
}
int main()
{
    while(~scanf("%d%d%s",&n,&t,c+1))
    {
        for(int i=1;i<=n;++i)dat[i]=c[i]=='H'?-1:c[i]=='S'?1:0;
        int l=0,r=0;
        for(int i=1;i<=n;++i)
        {
            if(dat[i]==-1)r++,last=i;
            if(dat[i]==1)l--;
        }
        l+=r;
        if(l<0)l=0;//shop 多
        if(last>t){ puts("-1");continue; }
        while(l<r)
        {
            int mid=(l+r)/2;
            if(OK(mid)) r=mid;
            else l=mid+1;
        }
        printf("%d\n",r);
    }
}

248E
f[u][i]u点有i个未用过的概率。

254E
f[i][j]第i天剩下j的食物。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值