2015百度之星初赛第二场(1005 dp,1004 数学)

序列变换

 
 Accepts: 695
 
 Submissions: 3322
 Time Limit: 2000/1000 MS (Java/Others)
 
 Memory Limit: 32768/32768 K (Java/Others)
Problem Description

我们有一个数列A1,A2...An,你现在要求修改数量最少的元素,使得这个数列严格递增。其中无论是修改前还是修改后,每个元素都必须是整数。 请输出最少需要修改多少个元素。

Input

第一行输入一个 T(1T10) ,表示有多少组数据

每一组数据:

第一行输入一个 N(1N105) ,表示数列的长度

第二行输入N个数 A1,A2,...,An

每一个数列中的元素都是正整数而且不超过 106

Output

对于每组数据,先输出一行

Case #i:

然后输出最少需要修改多少个元素。

Sample Input
2
2
1 10
3
2 5 4
Sample Output
Case #1:
0
Case #2:
1


思路:首先每个数减去它对应的下表,然后求最长上升子序列,减下表的目的是防止下面的情况发生:
加入序列是1,2,2,2,3,这样求上升子序列是3,也就是要修改2个,但是中间的两个2,变化范围又不能超过(1,3)那么这样求的也就不对,但是减掉之后,相当于给中间重复的数留下了修改的空间
#include<iostream>
#include<cstdio>
#include<string>
#include<cstring>
#include<vector>
#include<cmath>
#include<queue>
#include<stack>
#include<map>
#include<set>
#include<algorithm>
using namespace std;
const int maxn=100010;
const int INF=1000000100;
int a[maxn];
int g[maxn];
int dp[maxn];
int N;
int main()
{
    int T,cas=1;
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d",&N);
        for(int i=1;i<=N;i++)
        {
            scanf("%d",&a[i]);
            a[i]-=i;
        }
        int ans=0;
        for(int i=0;i<=N;i++)g[i]=INF;
        for(int i=1;i<=N;i++)
        {
            int k=upper_bound(g+1,g+1+N,a[i])-g;
            g[k]=a[i];
            ans=max(ans,k);
        }
        printf("Case #%d:\n%d\n",cas++,N-ans);
    }
    return 0;
}


魔法因子

 
 Accepts: 215
 
 Submissions: 1208
 Time Limit: 2000/1000 MS (Java/Others)
 
 Memory Limit: 32768/32768 K (Java/Others)
Problem Description

有人说:人类是自己一步步进化的,而数学是上帝亲手创造的。度度熊最近也正沉醉于数学之美中,它发现了一种神奇的数字,取名曰:魔法因子。

将因子记为X,如果有一些整数与这些因子做乘法后,结果仍然是整数,同时,结果数字的首位和末位会换交换位置,而其他位置上的数字恰好不变!这时X被认为是一个魔法因子。需要注意的是,用来相乘的这些整数不会含有前导0,但是如果交换的结果有前导0,又恰好是乘法的结果,这时仍然认为X是这个整数的魔法因子。度度熊认为1不是个魔法因子,因为所有的数都可以符合这个条件,这一点都不好玩。

比如,X = 3.1312,有1875 * 3.1312 = 5871。

度度熊现在希望知道对于一个因子X,究竟有多少个整数可以满足这个条件,使其成为魔法因子。由于它还不会长度超过10位数的乘法,只需要求出长度不超过10的整数即可。

Input

第一行一个整数T,表示包含T组数据。 每组数据包含一个实数 X(0<X<10,X1) ,同时为了避免精度问题,小数点后的数字不会超过6位。

Output

每组数据,对于每组数据,先输出一行

Case #i:

然后输出符合条件的整数的个数,如果个数不为0,在第二行输出所有符合条件的整数,按数字大小升序排列,用空格隔开,如果个数为0,只输出一行。

Sample Input
3
3.1312
3.1415
0.3
Sample Output
Case #1:
3
1875 1876875 1876876875 
Case #2:
0 
Case #3:
2
1428570 2857140

思路:设符合条件的数的最高位是h,最低位是l,中间不变的部分为mid,由题意可得到下面的公式(这里对X乘上1e6用a表示,b表示1e6)

(h*power+l+mid)*a=(l*power+h+mid)*b

可推得:mid=((h*power+l)*a-(l*power+h)*b)/(a-b);

所以可以枚举h,l然后求mid,注意mid的最低位一定是0,因为留出最低位加l或者h

#include<iostream>
#include<cstdio>
#include<string>
#include<cstring>
#include<vector>
#include<cmath>
#include<queue>
#include<stack>
#include<map>
#include<set>
#include<algorithm>
using namespace std;
typedef long long LL;

const int maxn=20;

double x;
vector<LL> ans;
int main()
{
    int T,cas=1;
    scanf("%d",&T);
    while(T--)
    {
        scanf("%lf",&x);
        LL a=LL(x*1e6+0.1);
        LL b=1e6;
        ans.clear();
        for(int len=2;len<=10;len++)
        {
            LL power=1;
            for(int j=1;j<len;j++)power*=10;
            for(int h=1;h<=9;h++)
            {
                for(int l=0;l<=9;l++)
                {
                    LL offset=(power*l+h)*b-(power*h+l)*a;
                    if(offset%(10*(a-b))==0)
                    {
                        LL mid=offset/10/(a-b),tmpmid=mid;
                        if(tmpmid<0)continue;
                        int cnt=0;
                        while(tmpmid)
                            cnt++,tmpmid/=10;
                        if(cnt<=len-2)ans.push_back(power*h+mid*10+l);
                    }
                }
            }
        }
        printf("Case #%d:\n",cas++);
        printf("%d\n",ans.size());
        int len=ans.size();
        for(int i=0;i<len;i++)
        {
            printf("%I64d",ans[i]);
            if(i!=len-1)printf(" ");
            else printf("\n");
        }
    }
    return 0;
}

追星族

 
 Accepts: 21
 
 Submissions: 122
 Time Limit: 6000/3000 MS (Java/Others)
 
 Memory Limit: 32768/32768 K (Java/Others)
Problem Description

度度熊最近迷上了S明星,恰逢她正在巡回演出,得知所有的演出安排后,它希望一场不落的看完所有的演出。

每场演出的地点  (Xi,Yi)  以及时间 Ti ,这些信息事先都已经公布。但唯一的问题是,单位时间内度度熊的移动速度只有可怜的1。它当然希望离自己的偶像越近越好,所以它希望在所有的演出时刻,它距离演出地点距离的最大值可以最小。度度熊在时间点0时刻出发,并且它可以选择任何一个位置作为起点。

生活在一个格子化的二次元中,度度熊是这样计算距离的: |x1x2|+|y1y2|

Input

第一行一个整数T,表示T组数据。

每组样例的第一行有一个整数 N(1N50000) ,表示演出的场数。

接下来的N行,每行包括三个整数 Xi,Yi,Ti(109Xi,Yi109,0Ti109) ,描述一场演出的地点与时间。数据中存在演出时间相同或者演出地点相同的数据。

Output

对于每组数据,输出两行:

第一行输出:"Case #i:"。i代表第i组测试数据。

第二行输出最小的最大距离。为了尽量精确,用分数A/B的形式表示,其中A和B不可继续化简。

Sample Input
2
2
1 1 2
1 5 1
2
1 1 2
1 5 10
Sample Output
Case #1:
3/2
Case #2:
0/1

下面的代码是比赛时过了的

#include <cstdlib>
#include <cctype>
#include <cstring>
#include <cstdio>
#include <cmath>
#include <algorithm>
#include <vector>
#include <string>
#include <iostream>
#include <sstream>
#include <map>
#include <set>
#include <queue>
#include <stack>
#include <fstream>
#include <numeric>
#include <iomanip>
#include <bitset>
#include <list>
#include <stdexcept>
#include <functional>
#include <utility>
#include <ctime>
#include <cassert>
#include <complex>
using namespace std;
#define rep(i,a,n) for (int i=a;i<n;i++)
#define per(i,a,n) for (int i=n-1;i>=a;i--)
#define pb push_back
#define mp make_pair
#define all(x) (x).begin(),(x).end()
#define fi first
#define se second
typedef long long ll;
typedef pair<ll,ll> PLL;
typedef vector<ll> VL;
const ll mod=1000000007;

const int N=50100;
int _,n,__;
ll x[N],y[N],t[N],inf=1ll<<60;
PLL p[N],q[N];
ll solve(pair<ll,ll> *p) {
    sort(p,p+n);
    ll ret=0;
    ll l=p[0].se,r=p[0].se;
    rep(i,1,n) {
        l-=(p[i].fi-p[i-1].fi);
        r+=(p[i].fi-p[i-1].fi);
        l=max(l,p[i].se); r=min(r,p[i].se);
        ret=max(ret,l-r);
    }
    return ret;
}
int main() {
    for (scanf("%d",&_);_;_--) {
        scanf("%d",&n);
        rep(i,0,n) scanf("%I64d%I64d%I64d",x+i,y+i,t+i);
        rep(i,0,n) p[i]=mp(t[i],x[i]+y[i]);
        rep(i,0,n) q[i]=mp(t[i],x[i]-y[i]);
        ll ret=max(solve(p),solve(q));
        printf("Case #%d:\n",++__);
        if (ret<0) puts("0/1");
        else {
            if (ret%2==0) printf("%I64d/1\n",ret/2);
            else printf("%I64d/2\n",ret);
        }
    }
}
#include <stdio.h>
#include <stdlib.h>
#include <iostream>
#include <algorithm>
#include <cstring>
#define Max(a, b) ((FASTBUFFER = ((a) - (b)) >> 31), ((b) & FASTBUFFER | (a) & ~FASTBUFFER))
#define Min(a, b) ((FASTBUFFER = ((a) - (b)) >> 31), ((a) & FASTBUFFER | (b) & ~FASTBUFFER))
#define Swap(a, b) (a ^= b, b ^= a, a ^= b)
#define OO 2147483647
#define priority_queue PQ

using namespace std;

int FASTBUFFER;

int test, tt, n;

const int N = 50005;

struct Point {
    long long x, y, t;

    friend bool operator < (const Point &a, const Point &b) {
        return a.t < b.t;
    }

    void read() {
        int xx, yy;
        scanf("%d %d %I64d", &xx, &yy, &t);
        t <<= 1;
        x = xx + yy;
        y = xx - yy;
        x <<= 1;
        y <<= 1;
    }
} p[N];

struct rec {
    long long x1, y1, x2, y2;

    void expand(long long d) {
        x1 -= d;
        y1 -= d;
        x2 += d;
        y2 += d;
    }
};

struct rec intersect(const rec &a, const rec &b) {
    rec ret;
    ret.x1 = max(a.x1, b.x1);
    ret.x2 = min(a.x2, b.x2);
    ret.y1 = max(a.y1, b.y1);
    ret.y2 = min(a.y2, b.y2);
    return ret;
}

int ok(long long ans) {
    rec now;
    now.x1 = now.x2 = p[1].x;
    now.y1 = now.y2 = p[1].y;
    now.expand(ans);
    for (int i = 2; i <= n; i++) {
        now.expand(p[i].t - p[i - 1].t);
        rec temp;
        temp.x1 = temp.x2 = p[i].x;
        temp.y1 = temp.y2 = p[i].y;
        temp.expand(ans);
        now = intersect(now, temp);
        if (now.x1 > now.x2 || now.y1 > now.y2) {
            return 0;
        }
    }

    return 1;
}

void work() {
    scanf("%d", &n);
    for (int i = 1; i <= n; i++) {
        p[i].read();
    }

    sort(p + 1, p + n + 1);
    long long l = 0, r = 10000000000LL;
    while (l < r) {
        long long mid = (l + r) >> 1;
        if (ok(mid)) {
            r = mid;
        } else {
            l = mid + 1;
        }
    }

    if (!(l & 1)) {
        printf("%I64d/1\n", l / 2);
    } else {
        printf("%I64d/2\n", l);
    }
}

int main() {
    scanf("%d", &test);
    while (test--) {
        printf("Case #%d:\n", ++tt);
        work();
    }

    return 0;
}



  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值