ACM题集:https://blog.csdn.net/weixin_39778570/article/details/83187443
题目集合:http://acm.hdu.edu.cn/listproblem.php?vol=11
2041 超级楼梯
简单的递推注意初始条件
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define P pair<int, int>
int dp[100];
void init(){
dp[1] = 1; // 刚开始在第一级
dp[2] = 1;
for(int i=3; i<100; i++)
dp[i] = dp[i-1] + dp[i-2];
dp[1] = 0;
}
int n, a;
int main(){
init();
scanf("%d", &n);
while(n--){
scanf("%d",&a);
printf("%d\n", dp[a]);
}
return 0;
}
2042 不容易系列之二
/* f(x)在第几个站羊的数量 /
/ f(x) - f(x)/2 + 1 = f(x+1)
f(x) = 2 * (f(x+1) -1) */
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define P pair<int, int>
int dp[50];
void init(){
dp[0] = 3; // 倒过来计数,终点数量
for(int i=1; i<50; i++)
dp[i] = 2*(dp[i-1]-1);
}
int n, a;
int main(){
init();
scanf("%d", &n);
while(n--){
scanf("%d",&a);
printf("%d\n", dp[a]);
}
return 0;
}
2043 密码
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define P pair<int, int>
bool safety(const char *s){
int len = strlen(s);
if(len<8 || len>16) return 0; // 判断1
const char *prt = s;
bool ok1=0,ok2=0,ok3=0,ok4=0;
int cnt = 0;
while(*prt!=0){ // 记得解引用 ,结束符为0
if(*prt>='A' && *prt<='Z') {
if(!ok1) {
cnt++;
ok1 = 1;
}
}
else if(*prt>='a' && *prt<='z') {
if(!ok2) {
cnt++;
ok2 = 1;
}
}
else if(*prt>='0' && *prt<='9') {
if(!ok3) {
cnt++;
ok3 = 1;
}
}
else if(*prt=='~' || *prt=='!' || *prt=='@' || *prt=='#' || *prt=='$' || *prt=='%' || *prt=='^') {
if(!ok4) {
cnt++;
ok4 = 1;
}
}
if(cnt>=3) return 1;
prt++;
}
return cnt>=3;
}
int n;
char c[100];
int main(){
scanf("%d", &n);
while(n--){
scanf("%s", c);
if(safety(c)) printf("YES\n");
else printf("NO\n");
}
return 0;
}
2044 一只小蜜蜂…
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define P pair<int, int>
ll dp[55]; // 注意溢出情况
void init(){
dp[1] = 1;
dp[2] = 2;
for(int i=3; i<=50; i++){
dp[i] = dp[i-1]+dp[i-2];
}
}
int n,a,b;
int main(){
init();
scanf("%d", &n);
while(n--){
scanf("%d%d", &a,&b);
printf("%lld\n", dp[b-a]);
}
}
2045 不容易系列之(3)—— LELE的RPG难题
第n-1种颜色如果跟第一种颜色不一样那么第n种只有一种颜色可以选
第n-1种颜色如果跟第一种颜色一样那么n有两种颜色可以选,与第n-2种可以选择的颜色一样
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define P pair<int, int>
ll dp[55]; // 注意溢出情况
void init(){
dp[1] = 3; dp[2] = 6; dp[3] = 6;
for(int i=4; i<=50; i++){
dp[i] = 2*dp[i-2] + dp[i-1];
}
}
int n;
int main(){
init();
while(scanf("%d",&n) != EOF){
printf("%lld\n", dp[n]);
}
return 0;
}
2046 骨牌铺方格
骨牌的长度只有2,它最多影响的范围是两列,在两列中寻找变化
当n-1列为竖直放置的时候n列只能竖直放置(一种情况)
当n-1列为水平放置的时候n列只能水平放置(一种情况)
#include<bits/stdc++.h>
using namespace std;
#define ll long long
ll dp[55];
void init(){
dp[1] = 1;
dp[2] = 2;
for(int i=3; i<=50; i++)
dp[i] = dp[i-1] + dp[i-2];
}
int n;
int main(){
init();
while(scanf("%d",&n)!=EOF) printf("%lld\n", dp[n]);
return 0;
}
2047 阿牛的EOF牛肉串
/*
当n-1个为EF时: 此时第n个 的选择为 f(n-2)23
当n-1个为O时 : 第n-1为o的数量为 f(n-1) - f(n-2)*2 即总数量减去EF数量
此时第n个 的选择为 (f(n-1) - f(n-2)2)2
相加化简得 : f(n) = 2f(n-1) +2f(n-2)
*/
#include<bits/stdc++.h>
#define ll long long
using namespace std;
ll dp[55];
void init(){
dp[1] = 3; dp[2] = 8;
for(int i=3; i<=40; i++) dp[i] = 2*dp[i-1] + 2*dp[i-2];
}
int n;
int main(){
init();
while(scanf("%d",&n)!=EOF)printf("%lld\n",dp[n]);
return 0;
}
2048 神、上帝以及老天爷
/*
错排问题:
1)把第n个元素放置第k位 有n-1种放法
2)把第k个元素放在第n位,这是剩下n-2种元素进行错排
不把第k个元素放在第n位,这时有n-1个元素进行错排
元素k不放在第n位,可以直接认为他就是第n位的元素,错排后他就不再第n位了
所以f(n) = (n-1) (f(n-1) + f(n-2))
f(n)表示有n个元素进行错排
*/
#include<bits/stdc++.h>
#define ll long long
using namespace std;
ll dp[30];
double gl[30];
void init(){
dp[1] = 0;
dp[2] = 1;
gl[1] = 1;
gl[2] = 0.5;
double sum = 2;
for(int i=3; i<=20; i++){
dp[i] = (i-1) * (dp[i-2]+dp[i-1]);
sum *= i;
gl[i] = dp[i]/sum;
//printf("%lld %f %f\n", dp[i], sum, gl[i]);
}
}
int n,a;
int main(){
init();
scanf("%d", &n);
while(n--){
scanf("%d",&a);
printf("%.2f%%\n", gl[a]*100); // 两个%输出一个%
}
return 0;
}
2049 不容易系列之(4)——考新郎
组合加错排 小数据
#include<bits/stdc++.h>
#define FOR(i,j,n)for(int i=j; i<=n; ++i)
#define P pair<int,int>
#define ll long long
using namespace std;
ll c[30][30];
void init(){
FOR(i,0,20) c[i][0] = 1;
FOR(i,1,20){
FOR(j,1,i){
c[i][j] = c[i-1][j] + c[i-1][j-1];
}
}
}
ll dp[30];
void init1(){
dp[1] = 0; dp[2] = 1;
FOR(i,3,20) dp[i] = (i-1)*(dp[i-1]+dp[i-2]);
}
int main(){
init();
init1();
int t,a,b;
scanf("%d", &t);
while(t--){
scanf("%d%d", &a,&b);
printf("%lld\n",c[a][b]*dp[b]);
}
return 0;
}
2050 折线分割平面
递推求和
见几何篇
#include<bits/stdc++.h>
#define fo(i,j,n) for(int i=j; i<=n; i++)
#define ll long long
using namespace std;
int t,m;
int main(){
scanf("%d", &t);
while(t--){
scanf("%d", &m);
printf("%d\n", 2*m*m-m+1);
}
return 0;
}
2051 Bitset
10转2进制
#include<bits/stdc++.h>
#define fo(i,j,n) for(int i=j; i<=n; i++)
#define ll long long
using namespace std;
int n;
int a[1000];
void solve(ll n){
int cnt = 0;
while(n){
a[++cnt] = n&1;
n >>= 1;
}
for(int i=cnt; i>=1; i--)printf("%d", a[i]);
printf("\n");
}
int main(){
while(scanf("%d",&n)!=EOF){
solve(n);
}
return 0;
}
2052 Picture
绘制矩形
#include<bits/stdc++.h>
#define fo(i,j,n) for(int i=j; i<=n; i++)
#define ll long long
using namespace std;
int n,m;
void solve(int n, int m){
printf("%c", '+');
fo(i,1,n) printf("%c",'-');
printf("%c\n", '+');
fo(i,1,m){
printf("%c",'|');
fo(i,1,n) printf("%c",' ');
printf("%c\n",'|');
}
printf("%c", '+');
fo(i,1,n) printf("%c",'-');
printf("%c\n\n", '+');
}
int main(){
while(scanf("%d%d", &n,&m)!=EOF){
solve(n,m);
}
}
2053 Switch Game
求约数个数的奇偶问题
#include<bits/stdc++.h>
#define fo(i, j, n) for(int i=j; i<=n; i++)
#define ll long long
using namespace std;
int n;
int main(){
while(scanf("%d", &n)!=EOF){
int k = sqrt(n);
if(k*k==n)printf("1\n");
else printf("0\n");
}
return 0;
}
2054 A == B ?
#include<bits/stdc++.h>
#define fo(i, j, n) for(int i=j; i<=n; ++i)
#define ll long long
using namespace std;
char s1[1000000],s2[1000000];
string getStr(const char *p1){
string s1;
const char *ptr1 = p1;
// 头加正负
if(*ptr1!=0 && *ptr1 == '-') {
s1+="-";
ptr1++;
}
else if(*ptr1!=0 && *ptr1 == '+') {
s1 += "+";
ptr1++;
}
else if(*ptr1!=0){
s1 += "+";
}
// 去头0
while(*ptr1!=0 && *ptr1=='0')ptr1++;
// +0.1的情况 需要补头0
if(*ptr1!=0 && *ptr1=='.') s1 += "0";
// cout << s1 << endl;
// 小数点
while(*ptr1 != 0 && *ptr1!='.') {
s1 += *ptr1;
ptr1++;
}
// 小数点的位置 cout << ptr1-p1 << endl;
// 去小数点后面的0
if(*ptr1 != 0 && *ptr1=='.'){
int st = ptr1-p1+1; // 小数点后第一个位置
int j = strlen(p1);
int i=j-1; // 最终位置
for(; p1[i]!='.'&&p1[i]=='0'; --i);
if(i>st) s1 += ".";
for(int k=st; k<=i; ++k) s1 += p1[k];
}
return s1;
}
string g1,g2;
int main(){
while(scanf("%s%s", s1, s2) !=EOF){
g1 = getStr(s1);
g2 = getStr(s2);
// cout<< g1 <<endl;
// cout<< g2 <<endl;
if(strcmp(g1.c_str(),g2.c_str()) == 0)printf("YES\n"); // string 比较要变成字符数组
else printf("NO\n");
}
return 0;
}
2055 An easy problem
#include<bits/stdc++.h>
#define fo(i,j,n) for(int i=j; i<=n; ++i)
#define ll long long
using namespace std;
ll t, r, ans;
char c;
ll f(int c){
if(c>='A' && c<='Z') return c-'A'+1;
else return -(c-'a'+1);
}
int main(){
scanf("%lld", &t);
while(t--){
scanf("%s%d", &c,&r); // 注意缓存区 !!!!%s或者getchar()
ans = r+f(c);
cout<<ans<<endl;
}
return 0;
}
2056 Rectangles
#include<bits/stdc++.h>
#define fo(i,j,n) for(int i=j; i<=n; ++i)
#define ll long long
using namespace std;
typedef struct{
double x, y;
}NODE;
NODE a, b, c, d;
int main(){
while(scanf("%lf%lf%lf%lf%lf%lf%lf%lf", &a.x,&a.y,&b.x,&b.y,&c.x,&c.y,&d.x,&d.y)!=EOF){
double x1 = min(a.x,b.x);double y1 = min(a.y,b.y);
double x2 = max(a.x,b.x);double y2 = max(a.y,b.y);
double x3 = min(c.x,d.x);double y3 = min(c.y,d.y);
double x4 = max(c.x,d.x);double y4 = max(c.y,d.y);
double X1 = max(x1,x3); double Y1 = max(y1,y3);
double X2 = min(x2,x4); double Y2 = min(y2,y4);
if(X1<X2 && Y1<Y2) printf("%.2f\n", (X2-X1)*(Y2-Y1));
else puts("0.00");
}
return 0;
}
2058 The sum problem
/严格递增区间和问题 使用等差数列求和公式/
/最长长度sqrt(2m)计算*/
/*
1+…+k >= m
k(1+k)/2 >= m
k+k^2 >= 2m
令K^2 = k + k^2 则 K>k (k>=1)
则 1+2+…+K > m
故 最大连续长度不超过 K = sqrt(2m)
*/
#include<bits/stdc++.h>
#define ll long long
ll n, m;
int main(){
while(scanf("%lld%lld",&n,&m) && (n!=0||m!=0)){
for(int k=(int)sqrt(2*m); k>=1; k--){ // k长度
int a = m/k - (k-1)/2; // 浮点问题,利用等差公式和长度算出a(起点)
if(2*k*a+k*(k-1) == 2*m){ // 加一步判读,无除法不丢失精度
if(a<=n && a+k-1<=n) printf("[%d,%d]\n",a,a+k-1);
}
}
printf("\n");
}
return 0;
}
2059 龟兔赛跑
这道题目是DP中多阶段决策的典型例题
我们将起点和终点划分到N个加电站中去
这样一共有N+2点,用DP[i]表示到第i个加电站的最小耗费时间
那么在求DP[i]的时候,DP[0]…DP[i-1]已经求得
让j从0遍历到i-1,每一个j表示最后一次充电到i点
那么状态转移方程为
DP[i] = min(DP[j] + t(j, i)) //t(j, i)表示从j充完电一直到i点(中途没有充过电)
#include<bits/stdc++.h>
#define fo(i,j,n) for(int i=j; i<=n; ++i)
#define ll long long
using namespace std;
const double inf = 0xfffff;
double dp[105];
double L, Time;
int s[105];
int N,C,T,vr,vt1,vt2,len;
int main(){
while(scanf("%lf",&L)!=EOF){
scanf("%d%d%d", &N,&C,&T);
scanf("%d%d%d", &vr,&vt1,&vt2);
fo(i,1,N) scanf("%d", &s[i]);
s[0] = 0; s[N+1] = L; // 把起点和终点设置为加油站
dp[0] = 0; // 起点
fo(i,1,N+1){
dp[i] = inf;
fo(j,0,i-1){ // 在第j个站充电,后面不充电
len = s[i] - s[j];
if(len > C) Time = C*1.0/vt1 + (len-C)*1.0/vt2;
else Time = len*1.0 / vt1;
if(j>0) Time += T; // 第一个站不用充电时间
Time += dp[j];
dp[i] = min(dp[i],Time);
}
}
if(dp[N+1] > L*1.0/vr) printf("Good job,rabbit!\n");
else printf("What a pity rabbit!\n");
}
return 0;
}
2060 Snooker
#include<bits/stdc++.h>
#define fo(i,j,n) for(int i=j; i<=n; ++i)
using namespace std;
int t,m,p,o;
int main(){
scanf("%d", &t);
while(t--){
scanf("%d%d%d", &m,&p,&o);
if(m<=6){ // 白球不算,场上已经没有红球了
p += (15*m-m*m)/2;
}else{
p += (m-6)*8 + 27;
}
if(p>=o)puts("Yes");
else puts("No");
}
return 0;
}