题号 | 题目名称 |
---|---|
A | 捡石头 |
B | 魔法药水 |
C | 土地恢复 |
D | 组合数 |
E | 排数字 |
F | 小武的方程 |
A:
题目描述
地上有2N个石头,排成了一条线,相邻的石头距离为1,石头之间有着不同的大小,有N种大小不同 的石头,即相同大小的石头有2个,现将石头按照从小到大的顺序依次编号为1到N,有2个石头共享 相同的编号,现在小武和小林要同时从最左边的石头出发,按照石头大小依次捡起编号为1到N的石 头,并且相同编号的石头同一个人只能捡起来一次,现在他们想把地上的石头都捡完,求两个人的行 走的最短距离和为多少?
输入格式
第一行一个正整数N 第二行2N个数,按照石头从左到右的顺序依次给出石头的编号
输出格式
一行一个数表示行走的最短距离和
正题:
我们先用桶来记录每个石子的位置,然后分类讨论:
- 小武走到第一个,小林走到第二个
- 小武走到第二个,小林走到第一个
来自Jackma_mayichao
那么转移方程就是:
a n s + = m i n ( a b s ( a [ i + 1 ] [ 1 ] − a [ i ] [ 1 ] ) + a b s ( a [ i + 1 ] [ 2 ] − a [ i ] [ 2 ] ) , a b s ( a [ i + 1 ] [ 2 ] − a [ i ] [ 1 ] ) + a b s ( a [ i + 1 ] [ 1 ] − a [ i ] [ 2 ] ) ) ans+=min(abs(a[i+1][1]-a[i][1])+abs(a[i+1][2]-a[i][2]),abs(a[i+1][2]-a[i][1])+abs(a[i+1][1]-a[i][2])) ans+=min(abs(a[i+1][1]−a[i][1])+abs(a[i+1][2]−a[i][2]),abs(a[i+1][2]−a[i][1])+abs(a[i+1][1]−a[i][2]))
#include<iostream>
#include<cstdio>
#include<cmath>
using namespace std;
int n;
int a[1001010][3];
int main()
{
scanf("%d", &n);
for(int i=1; i<=n*2; i++)
{
int x;
scanf("%d", &x);
a[x][0]++;
a[x][a[x][0]]=i;
}
int ans=a[1][1]+a[1][2]-2;
for(int i=1; i<n; i++)
ans+=min(abs(a[i+1][1]-a[i][1])+abs(a[i+1][2]-a[i][2]),abs(a[i+1][2]-a[i][1])+abs(a[i+1][1]-a[i][2]));
printf("%d", ans);
return 0;
}
B:
题目描述
小武的实验室里有一种魔法药水,这个药水有个很奇怪的性质,它只能在盛放的体积为2的幂次时保 持稳定,例如1,2,4,8。所以小武在实验室里放置了很多容积为2的幂次的瓶子,其中N瓶放有魔法药 水,第i瓶魔法药水的体积为2的L[i]次方。这天小武想要收拾一下实验室,小武想知道最少用多少个瓶 子能把实验室的药水装完。
假设小武有任意2的幂次容积的瓶子,并且每种瓶子的数量足够使用。
输入格式
第一行一个正整数N
第二行N个数,表示L[i]
输出格式
一行一个数表示最少需要多少个瓶子
正题:
这题我们开一个桶来记录它当前次幂的数量,然后没两个可以凑成一个更大的
#include<iostream>
#include<cstdio>
using namespace std;
int n;
int a[1001000];
int main()
{
scanf("%d", &n);
for(int i=1; i<=n; i++)
{
int x;
scanf("%d", &x);
a[x]++;
}
long long sum=0;
for(int i=0; i<1001000; i++)
{
if(a[i]==1)
sum++;
else
if(a[i]!=0)
{
a[i+1]+=a[i]/2;
sum+=a[i]%2;
}
}
printf("%lld", sum);
return 0;
}
C:
题目描述
宣文胜的家乡山西省是我国的产煤大省,因为长期挖煤导致了他家乡的某些地方出现了地陷的情况。 近几年国家大力开展环境整治和土地复耕,让人民不仅享受经济发展所带来的红利更要还老百姓绿水 青山。为了把这些地陷的土地恢复平整,他的家乡决定聘请他负责这项工作。
他负责恢复的是一条长度为n的土地,恢复土地的主要工作是填平下陷的地表。需要恢复的土地可以 看作是n块首尾相连的区域,一开始,第i块区域下陷的深度为di。宣文胜决定每天选择一段连续区间 [M, N] ,填充这段区间中的每块区域,让其下陷深度减少1。在选择区间时,需要保证,区间内的每 块区域在恢复前下陷深度均不为0 。
宣文胜希望你能帮他设计一种方案,可以在最短的时间内将整块土地的下陷深度都变为0。
输入格式
第一行输入一个整数n,表示恢复土地的长度。
第二行n个整数di,以空格隔开。
输出格式
输出一个整数,即最少需要多少天才能完成任务。
正题:
这题用贪心,每次找到一个比前一个数大的就相当于重新开一个坑,于是就把它们的差加上
#include<iostream>
#include<cstdio>
using namespace std;
long long n;
long long a[1001000];
int main()
{
scanf("%lld", &n);
long long last=0, sum=0;
for(long long i=1; i<=n; i++)
{
scanf("%lld", &a[i]);
if(a[i]>last)
sum+=a[i]-last;
last=a[i];
}
printf("%lld", sum);
return 0;
}
D:
正题:
预处理杨辉三角,每次转移时把相加后的值对k取模,用二维前缀和记录。
#include<iostream>
#include<cstdio>
using namespace std;
long long t, k;
long long a[2020][2020];
long long b[2020][2020];
void sandwich()
{
a[1][1]=1;
a[2][1]=1;
a[2][2]=1;
for(long long i=3; i<=2010; i++)
{
a[i][1]=a[i][i]=1;
b[i][1]+=b[i-1][1]+b[i][0]-b[i-1][0];
for(long long j=2; j<i; j++)
{
a[i][j]=(a[i-1][j]+a[i-1][j-1])%k;
if(a[i][j]==0)
b[i][j]=1;
b[i][j]+=b[i-1][j]+b[i][j-1]-b[i-1][j-1];
}
for(long long j=i; j<=2010; j++)
b[i][j]+=b[i-1][j]+b[i][j-1]-b[i-1][j-1];
}
}
int main()
{
scanf("%lld%lld", &t, &k);
sandwich();
while(t--)
{
long long n, m;
scanf("%lld%lld", &n, &m);
printf("%lld\n", b[n+1][min(n, m)+1]);
}
return 0;
}
E:
题目描述
小武有n个数字,这天小武想将数字理的顺一点,小武要把数字分组,每组的个数都是m,并且这m个 数字连续,小武想知道可以做到吗?
输入格式
第一行一个整数t表示数据组数 对于每组数据, 第一行两个整数n,m 第二行N个非负整数,表示数字
输出格式
如果可以做到输出“true”,否则输出“false”
正题:
用贪心的思想,每次找到一个没选的数,看以它开头能不能凑,如果不能就直接false
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
int n, m;
int a[100100];
bool f[10001];
int main()
{
int t;
scanf("%d", &t);
while(t--)
{
scanf("%d%d", &n, &m);
for(int i=1; i<=n; i++)
scanf("%d", &a[i]);
sort(a+1, a+1+n);
if(n%m!=0)
{
printf("false\n");
continue;
}
int begin=0;
int flag=1;
for(int i=1; i<=n/m; i++)
{
if(flag==0)
break;
int j=begin+1;
int k=a[j];
f[j]=1;
int s=1;
int t=0;
while(j<n&&s<m)
{
j++;
if(f[j]==1)
{
if(a[j]-k>1)
{
flag=0;
break;
}
}
else
{
if(a[j]-k>1)
{
flag=0;
break;
}
else
if(a[j]-k==1)
{
f[j]=1;
s++;
k=a[j];
}
else
if(a[j]==k&&t==0)
{
t=1;
begin=j-1;
}
}
}
if(t==0)
begin=j;
if(s!=m)
{
flag=0;
break;
}
}
if(flag==0)
printf("false\n");
else printf("true\n");
memset(f, 0, sizeof(f));
}
}
E:
题目描述
小武有2个方程,x|y=A,x+y=B,其中|为二进制或符号,x和y是未知数,A和B已知,小武想知道这个 方程是否有非负整数解。
输入格式
第一行一个整数T表示数据组数
接下来T行,每行两个数A和B
输出格式
T行,
若方程有解输出Possible,否则输出Impossible
正题:
我们直接让x等于A,那么B-A就是y的值(在满足第二个条件的情况下)
这时就让A和B-A异或一下,看等不等与A就可以了
#include<bits/stdc++.h>
using namespace std;
int t;
int main()
{
scanf("%d", &t);
while(t--)
{
long long a, b;
scanf("%lld%lld", &a, &b);
long long k=a|(b-a);
if((b>=a)&&k==a)
printf("Possible\n");
else
printf("Impossible\n");
}
return 0;
}