9.18 test solution.

9 篇文章 0 订阅
4 篇文章 0 订阅

1.完美的序列(sequence.cpp/c/pas)

时空限制

时间限制:

1s

空间限制:

64MB

题目描述

LYK认为一个完美的序列要满足这样的条件:对于任意两个位置上的数都不相同。然而并不是所有的序列都满足这样的条件。

于是LYK想将序列上的每一个元素都增加一些数字(当然也可以选择不增加),使得整个序列变成美妙的序列。

具体地,LYK可以花费 1 点代价将第 i 个位置上的数增加 1 ,现在LYK想花费最小的代价使得将这个序列变成完美的序列。

输入输出格式

输入格式:

第一行一个数 n,表示数字个数。

接下来一行 n 个数ai,表示LYK得到的序列。

输出格式:

一个数表示变成完美的序列的最小代价。

输入输出样例

输入样例:
4
1 1 3 2
输出样例:
3

说明

对于 30% 的数据 n5

对于 60% 的数据 n1000

对于 80% 的数据 n30000 ai3000

对于 100% 的数据 n100000 1ai100000


solution

  • 要代价尽可能小,可以贪心的去解决

  • 开一个 exist 数组用来判断一个数是否在原序列中

  • a 数组记录原序列中重复的数

  • 先把 a 从小到大排序,然后贪心的修改

  • 对于当前的 a[i] 肯定是要找不在原序列中并且大于 a[i] 的最小的数。

code

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long ll;
#define MAXN 100010

template<typename T>
inline void input(T &x) {
    x=0; T a=1;
    register char c=getchar();
    for(;c<'0'||c>'9';c=getchar())
        if(c=='-') a=-1;
    for(;c>='0'&&c<='9';c=getchar())
        x=x*10+c-'0';
    x*=a;
    return;
}

int a[MAXN],cntA;
bool exist[MAXN<<1];
//exist数组开两倍大小是为了防止下面RE
//最坏的情况是100000个100000,那样最大会到199999,开两倍就好了。
int main() {
    int n;
    input(n);
    for(int i=1,x;i<=n;i++) {
        input(x);
        if(exist[x]) {
            a[++cntA]=x;
            continue;
        }
        exist[x]=true;
    }
    if(cntA==0) {
        printf("0");
        return 0;
    }
    sort(a+1,a+cntA+1);
    int ans=0,nowA=1;
    for(int i=1;nowA<=cntA;i++) {
        if(i<a[nowA]||exist[i]) continue;
        ans+=i-a[nowA++];
    }
    printf("%d",ans);
    return 0;
}

2.LYK与实验室(lab.cpp/c/pas)

时空限制

时间限制:

5s

空间限制:

64MB

题目描述

LYK在一幢大楼里,这幢大楼共有 n 层,LYK初始时在第 a 层上。

这幢大楼有一个秘密实验室,在第 b 层,这个实验室非常特别,对LYK具有约束作用,即若LYK当前处于 x 层,当它下一步想到达 y 层时,必须满足 |xy|<|xb|,而且由于实验室是不对外开放的,电梯无法停留在第 b 层。 LYK想做一次旅行,即它想按 k 次电梯,它想知道不同的旅行方案个数有多少个。

两个旅行方案不同当前仅当存在某一次按下电梯后停留的楼层不同。

输入输出格式

输入格式:

一行 4 个数,n,a,b,k

输出格式:

一个数表示答案,由于答案较大,将答案对 1000000007 取模后输出。

输入输出样例

输入样例#1:
5 2 4 1
输出样例#1:
2
输入样例#2:
5 2 4 2
输出样例#2:
2
输入样例#3:
5 3 4 1
输出样例#3:
0

说明

对于 20% 的数据 n,k5

对于 40% 的数据 n,k10

对于 60% 的数据 n,k500

对于 90% 的数据 n,k2000

对于 100% 的数据 n,k5000


solution

  • f[i][j] 表示第 i 次按停在第 j 层的方案数。

  • sum[i][j]=k=1jf[i][k] ,也就是 f[i][j] 的前缀和

  • 首先明白一点,能到达楼层 j 的楼层肯定是一段区间

  • 这个区间怎么算呢。看上面的式子。

  • |xj|<|xb|= (xj)2<(xb)2

  • 化简得到: x(2b2j)<b2j2

  • 分类讨论一下:

  • b>j (2b2j)>0

  • 所以原式 =x<b2j22b2j=x<b+j2

  • 同理也可推出来当 b<j 时, x>b+j2

  • 因为 x 是个整数,所以上面那两个式子可以在化简一下即:

  • b>j 时, xb+j2 ,其中 表示向下取整。

  • b<j 时, xb+j2 , 其中 表示向上取整。

  • 这只是区间的一个边界,另一个怎么办?

  • b>j 时,另一个取 1 ,因为可能不能从1 j ,但是那样sum[i][1]的值就会是 0 ,不会对sum[i][x]的值有影响。

  • 同理,当 b<j 的时候,另一个直接取 n

  • 所以就可以列出下面的dp方程:

  • f[i][j]=sum[i1][r]sum[i1][l1]f[i1][j]

  • 其中

    l={1b+j2b>jb<j
    ,
    r={b+j2nb>jb<j

  • 所以 dp 方程可以写成这样

  • f[i][j]=sum[i1][b+j2]f[i1][j]sum[i1][n]sum[i1][b+j21]f[i1][j]b>jb<j

  • 最后 ans=i=1nf[k][i] ,当然还要mod

  • 然而这样写出来怕是会MLE,所以把 f sum 变成滚动数组。

code

#include<cmath>
#include<queue>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long ll;
#define MAXN 5010
#define mod 1000000007

template<typename T>
inline void input(T &x) {
    x=0; T a=1;
    register char c=getchar();
    for(;c<'0'||c>'9';c=getchar())
        if(c=='-') a=-1;
    for(;c>='0'&&c<='9';c=getchar())
        x=x*10+c-'0';
    x*=a;
    return;
}

int f[2][MAXN];
int sum[2][MAXN]; 

int main() {
    int n,a,b,k;
    input(n),input(a),input(b),input(k);
    f[0][a]=1;
    for(int i=a;i<=n;i++)
        sum[0][i]=1;
    for(int i=1;i<=k;i++) {
        int now=i%2,last=(i+1)%2;
        for(int j=1;j<=n;j++) {
            int &dp=f[now][j];
            if(j>b) {
                int l=ceil((j+b+1)*0.5),r=n;//l这么算是因为浮点误差,不这么写会WA一两个点
                dp=(sum[last][r]-sum[last][l-1]-f[last][j])%mod;
            } else if(j<b) {
                int r=floor((j+b-1)*0.5);
                dp=(sum[last][r]-f[last][j])%mod;
            }
            if(dp<0) dp=(dp+mod)%mod;//因为是减法取模,注意变成负数
            sum[now][j]=(sum[now][j-1]+dp)%mod;
        }
    }
    int ans=0;
    int end=k%2;
    for(int i=1;i<=n;i++)
        ans=(ans+f[end][i])%mod;
    printf("%d",ans%mod);
    return 0;
}

3.旅行(travel.cpp/c/pas)

时空限制

时间限制:

1s

空间限制:

64MB

题目描述

LYK想去一个国家旅行。这个国家共有 n 个城市,有些城市之间存在道路,我们假定这些道路长度都是 1 的,更准确的说,共有 m 条道路。

我们定义城市A与城市 B 的最短路为A B 的所有路径中,经过的道路最少的那条道路。最短路的长度为这条道路的所有道路长度之和,由于所有道路长度都为 1,因此假如 A B之间最短路的道路条数为 k ,则A B 的最短路长度为 k

我们定义整个国家的最短路为任意两个城市( A,B B,A 算作不同的点对)之间的最短路长度的和。

然而这个国家正处于危乱之中,极有可能一条道路会被恐怖分子炸毁。

LYK想知道,万一某条道路被炸毁了,整个国家的最短路为多少。若炸毁这条道路后整个国家不连通了,那么就输出“INF”(不加引号)。

输入输出格式

输入格式:

第一行两个数 n,m

接下来 m 行,每行两个数u,v,表示存在一条道路连接 u,v (数据保证不存在自环)。

输出格式:

输出 m 行,第 i 行的值表示当第 i 条道路被炸毁时,整个国家的最短路是多少,若图不连通,则输出“INF”。

输入输出样例

输入样例:

2 2
1 2
1 2

输出样例:

2
2

说明

对于20%的数据 n10 , nm100

对于 40% 的数据 1n<m100

对于 70% 的数据 1n100 , n<m3000

对于再另外 10% 的数据对于所有节点 i(1i<n) ,存在一条边连接 i i+1,且 n=m n100

对于再另外 10% 的数据对于所有节点 i(1i<n) ,存在一条边连接 i i+1,且 n=m n1000

对于再另外 10% 的数据对于所有节点 i(1i<n) ,存在一条边连接 i i+1,且 n=m n100000


solution

  • no solution.

code

  • no code

我会补上的

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值