1001 搬砖(dp)
1003 懒得写 暂空
1006 懒得写 暂空
1008 游乐园(贪心)
题意:把N块砖每次分成两摞,每次消耗的体力是两摞砖的差值,直到每摞只剩下一块砖,求消耗的最少体力。
思路:一开始摸不到头脑,不明白题目的意思,后来和别人讨论,一来明白了和整除2有关,二来是清楚了用DP的思想,清楚了原理,就迎刃而解了。
#include <iostream>
#include <algorithm>
#include <string.h>
using namespace std;
int dp[10000005];
int main(){
int t;
cin>>t;
memset(dp,0,sizeof(dp));
dp[2]=0;
dp[3]=1;
for(int i=4;i<=10000005;i++){
if(i%2==0)
dp[i]=dp[i/2]+dp[i/2];
else
dp[i]=dp[i/2]+dp[i/2+1]+1;
}
while(t--){
long long n;
cin>>n;
cout<<dp[n]<<endl;
}
return 0;
}
1002 洗衣服(水题)
题意:给定n天,和每天要洗的衣服数量,还给定三个标准a,b,c。当衣服数量小于a时继续积攒,当大于a时就立刻拿去洗,且不同数量的衣服需要支付不同的金额。求支付的金额数。
思路:是一道简单的模拟题,但是要注意的有两点,一是每次洗衣服都是把所有的衣服洗完,二是用scanf和printf,防止超时。
#include <iostream>
#include <algorithm>
#include <string.h>
using namespace std;
int main(){
int n,a,b,c;
while(scanf("%d%d%d%d",&n,&a,&b,&c)!=EOF){
int coin=0;
int sum=0;
for(int i=0;i<n;i++){
int t;
cin>>t;
sum+=t;
if(sum<a){
continue;
}
else if(sum>=a&&sum<b){
sum=0;
coin+=2;
}
else if(sum>=b&&sum<c){
sum=0;
coin+=3;
}
else if(sum>=c){
sum=0;
coin+=4;
}
}
printf("%d\n",coin);
}
return 0;
}
1003 懒得写 暂空
1004 质方数(模拟)
题意:给定一个数m,求一个质数n,使n*n最接近m,输出n*n。
思路:先打出质数表,然后对m开方,找到大于和小于m的第一个质数进行比较,看谁的平方最接近m。需要注意的是要处理特殊情况,如果开方之后恰好为质数,直接输出其本身。如果开方之后为1,则输出4。
#include <iostream>
#include <algorithm>
#include <string.h>
#include <math.h>
using namespace std;
int isprime[10010];
int prime[10010];
void is_Prime(){
int cnt=0;
isprime[0]=isprime[1]=1;
for(int i=2;i<=10005;i++){
if(isprime[i]==0)
prime[cnt++]=i;
for(int j=0;j<cnt&&prime[j]*i<=10005;j++){
isprime[prime[j]*i]=1;
if(i%prime[j]==0)
break;
}
}
}
int main(){
is_Prime();
int t;
scanf("%d",&t);
while(t--){
int n;
cin>>n;
int m=sqrt(n);
//cout<<m<<endl;
if(!isprime[m]){
cout<<m*m<<endl;
}
else if(m==1)
cout<<4<<endl;
else{
int a=m;
int b=m;
while(isprime[a]){
a++;
}
while(isprime[b]){
b--;
}
int sum=abs(n-a*a)<abs(n-b*b)?a*a:b*b;
cout<<sum<<endl;
}
}
return 0;
}
1005 ACM组队安排(dp)
题意:组队情况可以为1人1组,2人1组和3人1组,求给定n个人有几种分组方式。
思路:一开始上网搜到了集合划分算法,后来听阿洁哥讲了一下是和DP有关的,最后看了一下阿洁哥的代码,实在是佩服..如果已经求出n-1个人的分组方式,要求n个人的分组方式,则这第n个人可以1人1组,则分组方式为dp[n-1],如果第n个人和前面n-1个人中一个人分成2人组,则为dp[n-2]*(n-1),同理如果和前面n-2中两个人分成3人组,则为dp[n-3]*Cn-1 2。
#include <iostream>
#include <string.h>
#include <algorithm>
#include <stdio.h>
using namespace std;
long long dp[25];
int main(){
int n;
dp[1]=1;
dp[2]=2;
dp[3]=5;
for(int i=4;i<=20;i++)
dp[i]=dp[i-1]+dp[i-2]*(i-1)+dp[i-3]*(i-1)*(i-2)/2;
while(cin>>n&&n){
cout<<dp[n]<<endl;
}
return 0;
}
1007 油菜花王国(并查集)
题意:给定n个精灵和其能力值和m组关系,m组关系中给定两个数a,b,代表b精灵属于a精灵家族。如果家族中的精灵的能力值恰好为斐波那契数,则家族威望值+1。求最大的家族威望值。
思路:一上来就明确需要用到并查集+求斐波那契数。但是听信了别人的话选用了矩阵快速幂方法求斐波那契..其实根本用不到,因为第45项就已经超过题目要求的最大值了,所以直接递归求解就可以。坑爹在于提交了无数次都是WA...最后用阿洁哥的算法,即把威望在并查集的时候一起合并到父节点就AC了,也是醉...还要注意的是并查集最好返回的是f[x],如果返回x会超内存。
#include <iostream>
#include <cstring>
#include <cstdio>
using namespace std;
#define ll long long
ll fibo[50];
int f[1050];
int fa[1050];
void init(){
fibo[1] = 1;
fibo[2] = 1;
for(int i = 3; i <= 45; i++){
fibo[i] = fibo[i-2] + fibo[i-1];
}
}
int check(int n){
for(int i = 1; i <= 45; i++){
if(n == fibo[i])
return 1;
if(n < fibo[i])
return 0;
}
}
int find(int x)
{
if(x != fa[x])
fa[x] = find(fa[x]);
return fa[x];
}
void merge(int x,int y)
{
int a = find(x),b = find(y);
if(a != b){
fa[b] = a;
f[a] += f[b];
}
}
int main(){
init();
int n,m;
while(~scanf("%d%d",&n,&m)){
int u,v,t;
memset(f,0,sizeof(f));
memset(fa,0,sizeof(fa));
for(int i = 1; i <=n; i++){
fa[i] = i;
scanf("%d",&t);
f[i] = check(t);
}
for(int i = 0; i < m; i++){
scanf("%d%d",&u,&v);
merge(u,v);
}
int ans = 0;
for(int i = 1; i <= 1000; i++){
if(f[i] > ans){
ans = f[i];
}
}
printf("%d\n", ans);
}
}
1008 游乐园(贪心)
题意:小明有k元,游乐场有n个项目,给定每个项目需要花费钱数,求小明的钱最多可以用来玩多少项目。前提条件是小明的朋友推荐了m个项目,这m个项目是小明必须玩的,如果连玩这m个项目的钱都不够,则输出-1。
思路:一开始想用01背包,但是钱数的最大值太大,导致开数组的话会超内存。后来发现用简单的贪心就可以,注意的就是m个项目的钱要减去,且把这m个项目的钱数置0,或者用标记数组置1。然后将其余项目的花费排序,从小到大判断能否满足。
#include <iostream>
#include <algorithm>
#include <string.h>
#include <math.h>
using namespace std;
int cost[10005];
int main(){
int t;
scanf("%d",&t);
while(t--){
int n,m,k;
int cnt=0;
scanf("%d%d%d",&n,&m,&k);
for(int i=1;i<=n;i++){
scanf("%d",&cost[i]);
}
long long sum=0;//用long long不然会爆
for(int i=1;i<=m;i++){
int a;
scanf("%d",&a);
sum+=cost[a];
cost[a]=0;
}
if(sum<k){
k-=sum;
cnt+=m;
sort(cost+1,cost+n+1);
int i=0;
while(cost[i]==0)
i++;
for(;i<=n;i++){
if(cost[i]<k){
k-=cost[i];
cnt++;
}
else if(cost[i]==k){
cnt++;
break;
}
else
break;
}
cout<<cnt<<endl;
}
else if(sum==k){
cout<<m<<endl;
}
else{
cout<<"-1"<<endl;
}
}
return 0;
}