组队赛1(2017 JUST Programming Contest 3.0)

C
题意:输入n,m,k,x,s。n表示总共要操作n次,m表示有m种法术,k表示有n个英雄,x表示每次操作要耗费的时间,s表示总共有的能量总值,接下来一行有m个输入,表示法术i可以使每次操作耗费的时间变为axi,再接下来依然有m个输入,表示使用法术i所要花费的能量ayi,然后后面有k个输入,表示英雄i可以使要操作的次数减少bxi次,再后面的k个输入表示召唤英雄i所要耗费的能量值,题目要求你有1次使用法术和1次召唤英雄的机会(可以不使用),要你输出使用法术和英雄后(剩余操作数x剩余时间)的最小乘积,并且法术加英雄消耗的能量不能超过总能量值s。
题解:考虑到能量总值不能超过s,所以我们首先将法术和英雄按照能量值从小到大排序,淘汰掉能量大于s的项,那么,在A项能量大于B项能量的情况下,如果A项能够选区,由于B项的能量比A小,所以B项一定可以选取,那么假如法术B项ax值小于A项ax值,那么对于能量大的A项来说,由于时间ax值越小越好,A取B项的ax值将会更优,对于英雄,因为,如果B项的bx值大于A项的bx值,由于减少的次数bx值越多越好,A取B项的bx值将会更优,
然后我们从a,b数组中一个取数组首开始,一个取数组末开始,假如数组首的能量+数组末的能量>s,那么由于数组已经是升序,我们可以淘汰数组末的最后一项,接着比较,直到数组首的能量+数组末的能量<=s,ans可以取最优值。不理解的看代码吧。
Ps:由于这个题中有使用法术后时间反而比原来时间k更大的案例,所以也要考虑只选英雄和只选法术时的最优答案。

#include
#define ll long long
using namespace std;
ll cot,n,m,tim,meg;
struct node
{
    ll x,y;
}a[100005],b[100005];
bool cmp(node p1,node p2)
{
    return p1.ymeg) break;
            while(j>=1&&b[j].y+a[i].y>meg) j--;
            if(j>=1)
                ans=min(ans,a[i].x*(cot-b[j].x));
            else ans=min(ans,a[i].x*cot);
        }
        printf("%lld\n",ans);
    }
}

G:虽然这题表面上看起来非常 像字典树的题,但字典树却并不能A这道题,从题意可以看出最大有1e5个结点,这个时候我们要创建26x1e5个next指针,所以这题我们利用 数据结构课所学的知识,森林转换成二叉树,这样我们对于每个结点就只要创建l和r指针了,26x1e5就可以缩减到2x1e5,左结点代表字符走到下一层,右结点代表与它不相等并且同层的后缀。如果不明白怎么转换的请参考数据结构书本吧O(∩_∩)O。
标程:

#include
using namespace std;
struct node
{
    char x;
    int num,l,r;
}tree[100005];
int ans[100005],now;
char s[100005];
int Insert(int x,char y)
{
    if(!tree[x].l)
    {
        tree[x].l=++now;
        x=tree[x].l;
        tree[x].x=y;
        tree[x].num=1;
        return x;
    }
    int t=tree[x].l;
    while(tree[t].r!=0)
    {
        if(tree[t].x==y)
        {
            tree[t].num++;return t;
        }
        t=tree[t].r;
    }
    if(tree[t].x==y)
    {
        tree[t].num++;
        return t;
    }
    tree[t].r=++now;t=tree[t].r;tree[t].x=y;tree[t].num=1;
    return t;
}
int main()
{
    int t,n,q;
    scanf("%d",&t);
    while(t--)
    {
        memset(tree,0,sizeof(tree));
        memset(ans,0,sizeof(ans));
        now=0;
        scanf("%d%d",&n,&q);
        while(n--)
        {
            scanf("%s",s);
            int len=strlen(s),cnt=0;
            for(int i=len-1;i>=0;i--)
            {
                cnt=Insert(cnt,s[i]);
                ans[len-i]=max(ans[len-i],tree[cnt].num);
            }
        }
        while(q--)
        {
            int k;
            scanf("%d",&k);
            printf("%d\n",ans[k]);
        }
    }
}

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