目录:
T1:捡石头
T2:魔法药水
T3:土地恢复
T4:组合数
T5:排数字
T6:小武的方程
T1:捡石头
题目描述
地上有2N个石头,排成了一条线,相邻的石头距离为1,石头之间有着不同的大小,有N种大小不同 的石头,即相同大小的石头有2个,现将石头按照从小到大的顺序依次编号为1到N,有2个石头共享 相同的编号,现在小武和小林要同时从最左边的石头出发,按照石头大小依次捡起编号为1到N的石 头,并且相同编号的石头同一个人只能捡起来一次,现在他们想把地上的石头都捡完,求两个人的行 走的最短距离和为多少?
输入格式
第一行一个正整数N 第二行2N个数,按照石头从左到右的顺序依次给出石头的编号
输出格式
一行一个数表示行走的最短距离和
输入输出样例
输入 #1
3
1 1 2 2 3 3
输出 #1
9
输入 #2
4
2 2 3 4 4 1 1 3
输出 #2
33
输入 #3
3
1 3 1 2 3 2
输出 #3
11
分析:
可以用 d p dp dp做 也可以直接模拟
CODE:
#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
using namespace std;
int n,ans;
struct node{
int x,y;
}a[101000];
bool cmp(node l,node r)
{
if(l.x==r.x)return l.y<r.y;
return l.x<r.x;
}
int main(){
scanf("%d",&n);
for(int i=1;i<=2*n;i++)
{
scanf("%d",&a[i].x);
a[i].y=i;
}
sort(a+1,a+n*2+1,cmp);
ans=a[1].y-1+a[2].y-1;
for(int i=3;i<=n*2;i++)
ans=ans+abs(a[i].y-a[i-2].y);
printf("%d",ans);
}
T2:魔法药水
题目描述
小武的实验室里有一种魔法药水,这个药水有个很奇怪的性质,它只能在盛放的体积为2的幂次时保 持稳定,例如1,2,4,8。所以小武在实验室里放置了很多容积为2的幂次的瓶子,其中N瓶放有魔法药 水,第i瓶魔法药水的体积为2的L[i]次方。这天小武想要收拾一下实验室,小武想知道最少用多少个瓶 子能把实验室的药水装完。
假设小武有任意2的幂次容积的瓶子,并且每种瓶子的数量足够使用。
输入格式
第一行一个正整数N
第二行N个数,表示L[i]
输出格式
一行一个数表示最少需要多少个瓶子
输入输出样例
输入 #1
5
1 1 2 3 3
输出 #1
2
输入 #2
6
7 6 4 6 7 0
输出 #2
4
输入 #3
7
8 6 6 8 2 8 4
输出 #3
5
分析:
用桶记录当前幂的值 每两个可以组成一个更大的
CODE:
#include<cstdio>
#include<iostream>
#define ll long long
using namespace std;
int n,a[10000005],maxi;
ll ans;
int main()
{
scanf("%d",&n);
for(register int i=1;i<=n;i++)
{
int x;
scanf("%d",&x);
a[x]++;
maxi=max(maxi,x);
}
for(register int i=0;i<=maxi;i++)
{
if(a[i]>1)
{
a[i+1]+=a[i]/2;
a[i]%=2;
if(i==maxi) maxi++;
}
}
for(register int i=0;i<=maxi;i++)
if(a[i]) ans++;
printf ("%lld",ans);
return 0;
}
T3:土地恢复
题目描述
宣文胜的家乡山西省是我国的产煤大省,因为长期挖煤导致了他家乡的某些地方出现了地陷的情况。 近几年国家大力开展环境整治和土地复耕,让人民不仅享受经济发展所带来的红利更要还老百姓绿水 青山。为了把这些地陷的土地恢复平整,他的家乡决定聘请他负责这项工作。
他负责恢复的是一条长度为n的土地,恢复土地的主要工作是填平下陷的地表。需要恢复的土地可以 看作是n块首尾相连的区域,一开始,第i块区域下陷的深度为di。宣文胜决定每天选择一段连续区间 [M, N] ,填充这段区间中的每块区域,让其下陷深度减少1。在选择区间时,需要保证,区间内的每 块区域在恢复前下陷深度均不为0 。
宣文胜希望你能帮他设计一种方案,可以在最短的时间内将整块土地的下陷深度都变为0。
输入格式
第一行输入一个整数n,表示恢复土地的长度。
第二行n个整数di,以空格隔开。
输出格式
输出一个整数,即最少需要多少天才能完成任务。
输入输出样例
输入 #1
6
4 3 2 5 3 5
输出 #1
9
输入 #2
4
2 5 3 5
输出 #2
7
输入 #3
12
2 6 5 8 9 12 15 7 5 10 16 24
输出 #3
35
分析:
一个贪心 相邻的两个坑互相填 则小坑会被大坑带掉
大坑就减少了 a [ i ] − a [ i − 1 ] a[i]-a[i-1] a[i]−a[i−1]的高度
CODE:
#include<cstdio>
#include<iostream>
#include<algorithm>
using namespace std;
int n,sum,l;
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
int x;
scanf("%d",&x);
if(x>l)
sum+=(x-l);
l=x;
}
printf("%d",sum);
return 0;
}
T4:组合数
题目描述
输入格式
第一行有两个整数t,k,其中t表示该测试点总共有多少组测试数据,k的意义见「题目描述」。
接下来t行每行两个整数n,m,其中n,m的意义见「题目描述」。
输出格式
输出共t行,每行一个整数代表对于所有的 0 ≤ i ≤ n, 0 ≤ j ≤ min(i,m) 有多少对 (i, j) 满足 C(i,j)是k 的倍数。
输入输出样例
输入 #1
1 2
3 3
输出 #1
1
输入 #2
2 5
4 5
6 7
输出 #2
0
7
输入 #3
3 6
2 8
4 6
6 9
输出 #3
0
1
3
分析:
暴力枚举肯定是不行的 正解为预处理杨辉三角
然后做二维前缀和 每次 m o d mod mod k k k
CODE:
#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
#define ll long long
ll t,num[2002][2002];
int k,f[2002][2002];
void tri(){
f[0][0]=f[1][0]=f[1][1]=1;
for(int i=2;i<=2000;i++)
{
f[i][0]=1;
for(int j=1;j<=i;j++)
{
f[i][j]=(f[i-1][j-1]%k+f[i-1][j]%k)%k; //杨辉三角
num[i][j]=num[i-1][j]+num[i][j-1]-num[i-1][j-1]; //前缀和
if(f[i][j]==0) num[i][j]++;
}
num[i][i+1]=num[i][i];
}
}
int main (){
scanf("%lld%d",&t,&k);
tri();
while(t--)
{
int m,n;
scanf("%d%d",&n,&m);
if(m>n) printf("%lld\n",num[n][n]);
else printf("%lld\n",num[n][m]);
}
return 0;
}
T5:排数字
题目描述
小武有n个数字,这天小武想将数字理的顺一点,小武要把数字分组,每组的个数都是m,并且这m个 数字连续,小武想知道可以做到吗?
输入格式
第一行一个整数t表示数据组数 对于每组数据, 第一行两个整数n,m 第二行N个非负整数,表示数字
输出格式
如果可以做到输出 “ t r u e ” “true” “true”,否则输出 “ f a l s e ” “false” “false”
输入输出样例
输入 #1
3
9 3
1 2 3 6 2 3 4 7 8
6 3
1 2 3 4 6 7
6 3
1 2 3 4 5 6
输出 #1
true
false
true
分析:
模拟 每一个没选的数 判断如果以他开头能不能排出
如果不能直接 f a l s e false false 否则 t r u e true true
CODE:
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
int n,m,a[100105];
bool f[10005];
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;} //无法凑m组
int be=0,u=1;
for(int i=1;i<=n/m;i++)
{
if(u==0) break;
int j=be+1,k=a[j];
f[j]=1;
int qwq=1,T=0;
while(j<n&&qwq<m)
{
j++;
if(f[j]==1)
if(a[j]-k>1){
u=0;break;}
else
{
if(a[j]-k>1){
u=0;break;}
else
if(a[j]-k==1){
f[j]=1;qwq++;k=a[j];} //不断匹配
else
if(a[j]==k&&T==0){
T=1;be=j-1;}
}
}
if(T==0) be=j;
if(qwq!=m){
u=0;break;} //无法匹配m个
}
if(u==0) printf("false\n");
else printf("true\n");
memset(f,0,sizeof(f));
}
return 0;
}
T6:小武的方程
题目描述
小武有2个方程,x|y=A,x+y=B,其中|为二进制或符号,x和y是未知数,A和B已知,小武想知道这个 方程是否有非负整数解。
输入格式
第一行一个整数T表示数据组数
接下来T行,每行两个数A和B
输出格式
T行,若方程有解输出 P o s s i b l e Possible Possible,否则输出 I m p o s s i b l e Impossible Impossible
输入输出样例
输入 #1
4
14 14
2 5
0 9
10 10
输出 #1
Possible
Impossible
Impossible
Possible
分析:
把 x x x设为 A A A 则 y = B − A ( x + y = B ) y=B-A(x+y=B) y=B−A(x+y=B)
这样再把( A A A与 B − A B-A B−A异或一下) 判断等不等于 A A A即可
这样就不用 O ( T ∗ n 2 ) O(T*n^2) O(T∗n2) 去枚举 直接 O ( T ) O(T) O(T)过
CODE:
#include<iostream>
#include<cstdio>
using namespace std;
int t;
int main()
{
scanf("%d",&t);
while(t--)
{
long long a,b;
scanf("%lld%lld",&a,&b);
long long ans=a|(b-a);
if((b>=a)&&ans==a)
printf("Possible\n");
else
printf("Impossible\n");
}
return 0;
}