【题目记录】——上海站2011CCPC


题目集地址 上海站2011CCPC
队内题目集地址 上海站2011CCPC

A Zombie’s Treasure Chest 思维

题目地址A Zombie’s Treasure Chest
题目大意:有两种宝石蓝宝石和红宝石,数量不限,一个宝箱容量为N,每种宝石都有一个体积和价值,放入宝箱,问宝箱中宝石的最大价值是多少。
题目思路:看起来好像是一个完全背包,但是用完全背包的解法根本行不通,因为数据量都在( 2 3 1 2^31 231)也就是1e9,暴力肯定是不行的。
我们看这个题目S1,V1,S2,V2表示蓝宝石的体积和价值红宝石的体积和价值。然后我们看他们的性价比
关于分数的比较有一个小技巧:我一开始计算分数比较大小先通分,然后将分母化为相同的值比较分子大小,其实可以这样计算 如 果 V 1 S 1 > V 2 S 2 如果\frac{V1}{S1}>\frac{V2}{S2} S1V1>S2V2则两边同时乘一个S1S2则有 V 1 S 2 > V 2 S 1 V1S2>V2S1 V1S2>V2S1
我们枚举性价比较小的宝石,假设性价比小的是s1,我们找一个S1和S2的最小公倍数lcm。然后这个宝石的个数必然是小于 l c m / s 1 lcm/s1 lcm/s1的,因为如果等于它,那么我们就可以将这些宝石换成性价比更高的s2宝石。然后我们保证s1宝石的总体积不超过宝箱的总体积即可。
AC代码:

#include <bits/stdc++.h>
#define ll long long
#define INF 0x3f3f3f3f
using namespace std;
ll gcd(ll a, ll b)
{
    ll res=1;
    while(b)
    {
        res = a;
        a=b;
        b=res%b;
    }
    return a;
}
ll _lcm(ll a, ll b)
{
    return a*b/gcd(a,b);
}
void solve(int index)
{
    ll n,s1,v1,s2,v2;
    cin >>n>>s1>>v1>>s2>>v2;
    if(v1*s2<v2*s1)
    {
        swap(v1,v2);
        swap(s1,s2);
    }
    ll lcm = _lcm(s1,s2);
    ll ans=0;
    for(int i = 0;i < lcm/s2&&i*s2<=n;i++)
    {
        ans=max(ans,i*v2+(n-i*s2)/s1*v1);
    }
    cout <<ans<<endl;
}
int main()
{
    int t;
    scanf("%d",&t);
    for(int i = 1; i <= t; i++)
    {
        cout <<"Case #"<<i<<": ";
        solve(i);
    }
    return 0;
}

I Revenge of Fibonacci(trie树+数学基础)

题目地址Revenge of Fibonacci
题目大意:T组测试样例,问你一个数字串是哪个斐波那契数列的前缀,要求下标要最小
思路:参考HDU4099-Revenge of Fibonacci(trie树+数学基础)
先算斐波那契数,因为数字较大,所以要用大数模板,考虑到询问的数字串最多为40个,所以在插入trie树时可以选择插入<=40个,这样可以节省很大的内存。好吧,字典树我还不会做,后面补一下。
AC代码:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <vector>
#include <string>
#include <algorithm>
#include <queue>
using namespace std;
const int maxn = 7000000;
const int INF = 1e8;
int ch[maxn][10];
int val[maxn];
int cnt;
char c[200];
char str[200];
void add(char a[],char b[],char back[]){
 
    int i=strlen(a)-1,j=strlen(b)-1,k=0;
    int x,y,z;
    int up=0;
    while(i>=0||j>=0)
    {
        if(i<0)x=0;
        else x=a[i]-'0';
        if(j<0)y=0;
        else y=b[j]-'0';
        z=x+y+up;
        c[k++]=z%10+'0';
        up=z/10;
        i--;
        j--;
    }
    if(up>0)c[k++]=up+'0';
    for(i=0;i<k;i++)back[i]=c[k-1-i];
    back[k]='\0';
}
int getIdx(char  a){
    return a-'0';
}
void insert(char st[],int d){
    int u = 0;
    for(int i = 0; i < strlen(st) && i < 42; i++){
        int k = getIdx(st[i]);
        if(!ch[u][k]){
            val[cnt] = d;
            ch[u][k] = cnt++;
            memset(ch[cnt],0,sizeof ch[cnt]);
        }
        u = ch[u][k];
    }
}
int query(char st[]){
    int u = 0;
    for(int i = 0; i < strlen(st); i++){
        int k = getIdx(st[i]);
        if(!ch[u][k]){
            return -1;
        }
        u = ch[u][k];
    }
    return val[u];
}
void init(){
    cnt = 1;
    memset(ch[0],0,sizeof ch[0]);
    for(int i = 0; i < maxn; i++)
        val[i] = INF;
    char a[200],b[200],ans[200];
    a[0] = '1',a[1] = 0;
    b[0] = '1',b[1] = 0;
    insert(a,0);
    for(int i = 2; i < 100000; i++){
        if(strlen(b) > 70){
            a[strlen(a)-1] = 0;
            b[strlen(b)-1] = 0;
        }
        add(a,b,ans);
        insert(ans,i);
        strcpy(a,b);
        strcpy(b,ans);
    }
}
int main(){
    init();
    int ncase,T=1;
    cin >> ncase;
    while(ncase--){
        cin >> str;
        printf("Case #%d: %d\n",T++,query(str));
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值