解题报告
前言
这一章主要讲的是贪心和搜索
洛谷 1208 混合牛奶 Mixing Milk
题目
n n n个种类, a i a_i ai表示单价, b i b_i bi表示数量, 1 ≤ i ≤ n 1\leq i\leq n 1≤i≤n,数量如果只选择部分,价格仍然不变,问买 m m m个最少需要的价钱
分析
选择单价更小的必然更优,所以说其实很容易想到按单价递增排序后的模拟过程
代码
/*
ID:lemond1
LANG:C++
TASK:milk
*/
#include <cstdio>
#include <algorithm>
#define rr register
using namespace std;
struct rec{
int w,c;
bool operator <(const rec &a)const{
return w<a.w;
}
}a[5001];
inline signed in(){
rr int ans=0; rr char c=getchar();
while (c<48||c>57) c=getchar();
while (c>47&&c<58) ans=(ans<<3)+(ans<<1)+c-48,c=getchar();
return ans;
}
signed main(){
freopen("milk.in","r",stdin);
freopen("milk.out","w",stdout);
rr int n,m,ans=0;
m=in(); n=in();
for (rr int i=1;i<=n;++i) a[i]=(rec){in(),in()};
sort(a+1,a+1+n);
for (rr int i=1;i<=n&&m;++i)
if (a[i].c>=m) ans+=m*a[i].w,m=0;//如果直接可以满足供应完
else ans+=a[i].c*a[i].w,m-=a[i].c;//只能买完还需要买
printf("%d\n",ans);
return 0;
}
洛谷 1209 修理牛棚 Barn Repair
题目
在一个数轴用最多 m m m条任意长度的胶带封住 n n n个缺口,问胶带总长度的最小值
分析
可以知道,缺口位置的差值越大,越应该分开,所以说贪心的思想就是一开始认为全部用一条封上,然后不断揭开
代码
/*
ID:lemond1
LANG:C++
TASK:barn1
*/
#include <cstdio>
#include <algorithm>
#define rr register
using namespace std;
int a[201],b[201];
inline signed in(){
rr int ans=0; rr char c=getchar();
while (c<48||c>57) c=getchar();
while (c>47&&c<58) ans=(ans<<3)+(ans<<1)+c-48,c=getchar();
return ans;
}
signed main(){
freopen("barn1.in","r",stdin);
freopen("barn1.out","w",stdout);
rr int lm=in();in();rr int n=in();
for (rr int i=1;i<=n;++i) a[i]=in();
sort(a+1,a+1+n);
if (lm>=n) return !printf("%d\n",n);//特判
for (rr int i=1;i<n;++i) b[i]=a[i+1]-a[i];//计算不封中间的差值
sort(b+1,b+n); rr int ans=a[n]-a[1]+1;
for (rr int i=n-1;i>n-lm;--i) ans-=b[i]-1;//要少减掉1
return !printf("%d\n",ans);
}
洛谷 1211 牛式 Prime Cryptarithm
题目
分析
暴力枚举,在此不多赘述
代码
/*
ID:lemond1
LANG:C++
TASK:crypt1
*/
#include <cstdio>
#define rr register
using namespace std;
int n,a[10],ans;
inline signed check(int x,int len){//计算是否只存在这几个数字且满足位数
while (x){
if (!a[x%10]) return 0;
x/=10; len--;
}
return !len;
}
signed main(){
//freopen("crypt1.in","r",stdin);
//freopen("crypt1.out","w",stdout);
scanf("%d",&n);
for (rr int i=1,x;i<=n;++i) scanf("%d",&x),a[x]=1;
for (rr int i=1;i<10;++i) if (a[i])
for (rr int j=1;j<10;++j) if (a[j])
for (rr int k=1;k<10;++k) if (a[k])
for (rr int p=1;p<10;++p) if (a[p]&&check((i*100+j*10+k)*p,3))
for (rr int q=1;q<10;++q) if (a[q]&&check((i*100+j*10+k)*q,3))
if (check((i*100+j*10+k)*(p*10+q),4)) ++ans;
return !printf("%d\n",ans);
}
洛谷 2693 Combination Lock 号码锁
题目
分析
so其实问题可以转换成250-重复的个数,那么重复的个数也就是可以通过乘法原理算出,就是两个号码的交集
代码
/*
ID:lemond1
LANG:C++
TASK:combo
*/
#include <cstdio>
#define min(a,b) ((a)<(b))?(a):(b)
#define rr register
using namespace std;
signed main(){
freopen("combo.in","r",stdin);
freopen("combo.out","w",stdout);
rr int n,a,b,c,d,e,f;
scanf("%d%d%d%d%d%d%d",&n,&a,&b,&c,&d,&e,&f);
if (n<5) return !printf("%d\n",n*n*n);
if (a>d) a^=d,d^=a,a^=d;
if (b>e) b^=e,e^=b,b^=e;
if (c>f) c^=f,f^=c,c^=f;
rr int t1=min(d-a,a+n-d),t2=min(e-b,b+n-e),t3=min(f-c,c+n-f);
printf("%d\n",250-(5-t1)*(t1<5)*(5-t2)*(t2<5)*(5-t3)*(t3<5));
}
洛谷 3650 滑雪课程设计 Ski Course Design
题目
把 n n n个数变成 x x x到 x + 17 x+17 x+17的范围,变成 n ± y , y ∈ N ∗ n\pm y,y\in N* n±y,y∈N∗,需要 y 2 y^2 y2的价钱,每个数只能变1次,问最少价钱是多少 x 不 定 x不定 x不定
分析
讲到这里,暴力枚举x,然后模拟就不多说了
代码
/*
ID:lemond1
LANG:C++
TASK:skidesign
*/
#include <cstdio>
#define rr register
using namespace std;
int n,a[1001];
inline signed in(){
rr int ans=0; rr char c=getchar();
while (c<48||c>57) c=getchar();
while (c>47&&c<58) ans=(ans<<3)+(ans<<1)+c-48,c=getchar();
return ans;
}
signed main(){
freopen("skidesign.in","r",stdin);
freopen("skidesign.out","w",stdout);
n=in(); rr int ans=2147483647;
for (rr int i=1;i<=n;++i) a[i]=in();
for (rr int j=0;j<84;++j){
rr int sum=0;
for (rr int i=1;i<=n;++i)
if (a[i]<j) sum+=(j-a[i])*(j-a[i]);
else if (a[i]>j+17) sum+=(a[i]-j-17)*(a[i]-j-17);
ans=(ans<sum)?ans:sum;
}
return !printf("%d\n",ans);
}
洛谷 1444 虫洞 wormhole
题目
问一个无向关系图中有多少个环
分析
由于关系是不定的,所以对于虫洞的配对用深搜解决后,再判断是否形成环
代码
/*
ID:lemond1
LANG:C++
TASK:wormhole
*/
#include <cstdio>
#include <algorithm>
#define rr register
using namespace std;
struct site{
int x,y;
bool operator<(const site &a)const{
return (y!=a.y)?y<a.y:x<a.x;
}
}a[13];
int n,f[13],to[13],ans;
inline signed in(){
rr int ans=0; rr char c=getchar();
while (c<48||c>57) c=getchar();
while (c>47&&c<58) ans=(ans<<3)+(ans<<1)+c-48,c=getchar();
return ans;
}
inline signed rep(int x){
rr int vis=0;
while (to[x]){//判环
if (vis&(1<<x-1)) return 1;
vis|=(1<<x-1);
x=f[to[x]];
}
return 0;
}
inline void dfs(int dep){
if (dep>n){
bool flag=0;
for (rr int i=1;i<=n&&!flag;++i) flag=rep(i);
ans+=flag;
return;
}
if (f[dep]) dfs(dep+1);//如果已经找到虫洞了
else for (rr int i=dep+1;i<=n;++i)
if (!f[i]){
f[i]=dep; f[dep]=i;
dfs(dep+1);
f[i]=f[dep]=0;
}
}
signed main(){
freopen("wormhole.in","r",stdin);
freopen("wormhole.out","w",stdout);
n=in();
for (rr int i=1;i<=n;++i) a[i]=(site){in(),in()};
sort(a+1,a+1+n);
for (rr int i=1;i<n;++i) if (a[i].y==a[i+1].y) to[i]=i+1;
dfs(1);
return !printf("%d\n",ans);
}
后续
Fighting!