codeforces Hello 2018(A-E)

A题

题意:求m % 2n 的值

因为m的范围只有1e8,所以,只用看n小于30的范围就行了

B题

题意:一个树中,若非叶子节点没有大于或等于3个叶子节点相连的话,输出No,否则输出Yes

可以用bfs或者dfs来做呀,遍历一遍。
这里要注意的是dfs中不要掉return呀,虽然有时候本地机器会出来正确结果,但是到编译的时候可能会wa,或者会出现段错误想起来当初建树过程递归(指针)一个return都没写,程序没出问题,还是出了正确结果,可能知道我在想什么吧...

C题

题意:柠檬水,不同容量,会有不同价格,问要买不少于L升柠檬水,最少需要花的钱数.给定对应第i容量的价格,容量是 2i1 ,每种容量可以买任意次

开始的想法就是贪心,但是wa了,
然后感觉好像完全背包,看一眼范围,不行
然后感觉还是贪心…
思路就是按照单价排序,先尽量拿单价少的,如果超过了l容量,那么记录一下当前值,然后每次超过了,都记录一下值,最小的就是结果了
wa,,,
最后发现竟然是排序函数的问题???

bool cmp(node a1,node a2)
{
    if(abs(a1.per-a2.per)<eps) return a1.v>a2.v;
    return a1.per<a2.per;
}

如果单价相同的话,那么就按照体积从大道小,否则按照单价从小到大

去掉对单价相同的考虑就A了…

还有一个想法是和二进制有关的,感觉很巧妙呀~

#include <iostream>
#include <cstring>
#include <cstdio>
#include <cmath>
#include <algorithm>
#include <vector>
#include <queue>
#include <stack>

using namespace std;
#define mem(a,b) memset(a,b,sizeof(a))
#define ll long long
const double eps = 1e-6;
const ll inf = 1e18;
ll a[100];
int main()
{
    int n,l;
    scanf("%d %d",&n,&l);
    for(int i=0;i<n;i++)
        scanf("%I64d",&a[i]);
    for(int i=1;i<n;i++)
        a[i]=min(a[i],a[i-1]*2ll);
    for(int i=n-2;i>=0;i--)
        a[i]=min(a[i],a[i+1]);
    for(int i=n;i<=30;i++)
        a[i]=a[i-1]*2ll;
    ll ans = 0;
    int i=0;
    while(l)
    {
        if(l&1) ans = ans + a[i];
        i++;
        if(ans>a[i]) ans = a[i];
        l=l/2;
    }
    if(a[i]<ans) ans = a[i];
    printf("%I64d\n",ans);
    return 0;
}
D题

题意:就是有n个问题,限时是T,给出每个问题的ai和ti,ti表示需要消耗的时间。如果在T时间内解决了k个问题,那么m=解决的问题.ai>=k,的数量
求m最大为多少。

开始看了几遍题目都没懂….
这个的话,就是优先级队列,队列中放的就是解决的问题,且ai>=q.size();

#include <iostream>
#include <cstring>
#include <cstdio>
#include <cmath>
#include <algorithm>
#include <vector>
#include <queue>
#include <stack>

using namespace std;
#define mem(a,b) memset(a,b,sizeof(a))
#define ll long long
const int maxn = 2*100000+10;
struct node {
    int ai,ti,id;
    operator < (const node&temp)const {
        return ai>temp.ai;
    }
}a[maxn];
priority_queue<node>q;
bool cmp(node a1,node a2)
{
    return a1.ti<a2.ti;
}
int main()
{
    int n,t;
    scanf("%d %d",&n,&t);
    for(int i=1;i<=n;i++){
        scanf("%d %d",&a[i].ai,&a[i].ti);
        a[i].id = i;
    }
    sort(a+1,a+n+1,cmp);
    int i;
    for(i=1;i<=n;i++)
    {
        t-=a[i].ti;
        if(t<0) break;
        q.push(a[i]);
    }
    t+=a[i].ti;
    while(!q.empty())
    {
        node a1 = q.top();
        if(a1.ai<(q.size())) {q.pop();t+=a1.ti;}
        else break;
    }
    for(;i<=n;i++)
    {
        int temp = t-a[i].ti;
        if(temp<0) break;
        if(a[i].ai<(q.size()+1)) continue;//这个要先判断,然后才能加进去
        q.push(a[i]);
        t=temp;
        node a1 = q.top();
        if(a1.ai<(q.size())) {q.pop();t+=a1.ti;}
    }
    printf("%d\n",q.size());
    printf("%d\n",q.size());
    if(q.size()>=1){
        node a1 = q.top();
        printf("%d",a1.id);q.pop();
        while(!q.empty())
        {
            a1 = q.top();
            printf(" %d",a1.id);
            q.pop();
        }
    }
    printf("\n");
    return 0;
}
E题

题意:x=00001111b,y=00110011b,z=01010101b,有三种操作,按照优先级从高到题分别是!,&,|,还有一个(),给n个值,问对x,y,z进行怎样的操作可以变成给的值,输出表达式。

这个可以dp
F[i]:最后一步操作是!
T[i]:最后一步操作是&
E[i]:最后一步操作是|
状态转移:
F[i]可以转移到F[i^255]
F[i]可以直接转移到T[i]
T[i]可以转移到E[i]
E[i]可以转移到F[i](通过())
看不懂没关系,直接看代码,代码写的很清楚~

/*
by:sllsll
*/
#include <iostream>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <cstdio>
#include <vector>
#include <map>
#include <set>

using namespace std;
#define inf 0x3f3f3f3f
#define ll long long
#define mem(a,b) memsert(a,b,sizeof(a))
#define rep(a,b) for(int i=(a);i<(b);i++)
const int maxn = 1e5+10;
string F[maxn],T[maxn],E[maxn];
int x = 15,y=51,z=85;
int flag=0;
void fz(string&a,const string& b)
{
    if(a=="")
    {
        flag=1;
        a=b;return;
    }
    int size1 = a.length(),size2 = b.length();
    //最小字典序
    if(size1>size2) a = b,flag=1;
    else if(size1==size2)
        if(a>b)a=b,flag=1;

}
void dp()
{
    F[x]='x',F[y]='y',F[z]='z';
    while(1)
    {
        flag=0;
        rep(0,256)
            if(F[i]!="")
                fz(F[i^255],'!'+F[i]);
        for(int i=0;i<256;i++)
            if(F[i]!=""){
                fz(T[i],F[i]);
                for(int j=0;j<256;j++)
                    if(T[j]!="")
                        fz(T[i&j],F[i]+"&"+T[j]);
                }
        for(int i=0;i<256;i++)
            if(T[i]!=""){
                fz(E[i],T[i]);
                for(int j=0;j<256;j++)
                    if(E[j]!="")
                        fz(E[i|j],T[i]+"|"+E[j]);
            }
        for(int i=0;i<256;i++)
        if(E[i]!=""){
                fz(F[i],"("+E[i]+")");
        }
    if(!flag) break;
    }
}
int d[10]={128,64,32,16,8,4,2,1};
int change(string str)
{
    int ans = 0;
    for(int i=0;i<8;i++)
    {
        if(str[i]=='1') ans+=d[i];
    }
    return ans;
}
int main()
{
    dp();
    int T;
    scanf("%d",&T);
    while(T--)
    {
        string str;
        cin>>str;
        int n=change(str);
        cout<<E[n]<<endl;
    }
    return 0;
}

ps:临时变量作为引用型参数的时候要加const

还有一种做法最小生成树转移,感觉和这个差不多,也是先将所有值都计算出来,将这里的while(1)改成while(!q.empty()),然后是一样的转移

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值