目录
贪心:每次选择最大面值,扣到0时的cnt即为发放该工资所需最小数量
清楚汉字编码的特点:汉字码是小于0。并且一个汉字占两个字节(每一个字节均小于0)。
递推式,把前n-1层看成一个整体移动,故f[n] = 3 * f[n-1] + 2;
Dijkstra:这里可以把人看做0号顶点,到相邻城市的距离为0
二维数组的递推式(二维超级楼梯):要使得路径最小,每次仅往右或往下(好兔不走回头路)
atan求角度,注意对 正负四象限 两种情况区分讨论,本题以x正方向为基准
贪心:站在中间(左右房子数量相同),每次路程即为两端点最短距离(双指针)
输入样例等价为一个有向图,当仅有一个结点入度为0时,产生冠军
分析规律:补上 余数与除数的差额 ,即可得到当前最小可被整除的数
2018-母牛的故事
动态规划
第N年的母牛个数等于前一年的母牛数+四年前的母牛数
#include <cstdio>
using namespace std;
int main(void)
{
int n,m, sum1,sum2;
string s;
int arr[60];
while(scanf("%d",&n)!=EOF)
{
if (n == 0)break;
if (n <= 4) {
printf("%d\n",n);
continue;
}
arr[1] = 1;
arr[2] = 2;
arr[3] = 3;
arr[4] = 4;
for (int i = 5; i <= n; ++i) {
arr[i] = arr[i-1] + arr[i-3];
}
printf("%d\n",arr[n]);
}
return 0;
}
2020-绝对值排序
1.插入排序/冒泡排序
每插入一个数据,不断向前调整到合适的位置
#include <iostream>
#include <cstdio>
using namespace std;
static int arr[100];
void swap (int x, int y) //形参为数组索引
{
int t = arr[x];
arr[x] = arr[y];
arr[y] = t;
}
void insert_sort (int x, int index)
{
arr[index] = x;
for (int i = index; i > 0; i--) {
int abs_x = arr[i] > 0 ? arr[i] : -arr[i];
int abs_y = arr[i-1] > 0 ? arr[i-1] : -arr[i-1];
if (abs_x > abs_y) swap(i,i-1);
else return;
}
}
int main(void)
{
int n, num;
while(scanf("%d",&n) != EOF)
{
if (n == 0) break;
for (int i = 0; i < n; ++i) {
scanf("%d",&num);
insert_sort(num,i);
}
for (int i = 0; i < n; ++i) {
i == (n-1) ? printf("%d\n",arr[i]) : printf("%d ",arr[i]);
}
}
return 0;
}
2.双指针
i指向对头,j指向队尾,每次输出较大的数。
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 110;
int a[N];
int main()
{
int n;
while(scanf("%d", &n))
{
if(!n) return 0;
for (int i = 1; i <= n; i ++ ) scanf("%d", &a[i]);
sort(a+1,a+n+1);
for(int i = 1, j = n; i <= j; )
{
if(i == j) printf("%d\n",a[i++]);
else if(abs(a[i]) > abs(a[j])) printf("%d ",a[i++]);
else printf("%d ",a[j--]);
}
}
return 0;
}
2021-发工资咯
贪心:每次选择最大面值,扣到0时的cnt即为发放该工资所需最小数量
#include <iostream>
#include <cstdio>
using namespace std;
int main(void)
{
int n, money, sum;
while(scanf("%d",&n) != EOF)
{
if (n == 0) break;
sum = 0;
for (int i = 0; i < n; ++i) {
int cnt = 0;
scanf("%d",&money);
while (money)
{
if (money - 100 >= 0) money -= 100;
else if (money - 50 >= 0) money -= 50;
else if (money - 10 >= 0) money -= 10;
else if (money - 5 >= 0) money -= 5;
else if (money - 2 >= 0) money -= 2;
else money -= 1;
cnt ++;
}
sum += cnt;
}
printf("%d\n",sum);
}
return 0;
}
2022-海选女主角
遍历二维数组
#include <iostream>
#include <cstdio>
using namespace std;
int m,n,r,c;
double val = 0;
double x;
double get_abs (double a){
return a > 0 ? a : -a;
}
int main(void)
{
while(scanf("%d%d",&m,&n) != EOF)
{
for (int i = 0; i < m; ++i) {
for (int j = 0; j < n; ++j) {
scanf("%lf",&x);
if (get_abs(x) > get_abs(val))
{
val = x;
r = i;
c = j;
}
}
}
printf("%d %d %.0f\n",r+1,c+1,val);
val = 0;
}
return 0;
}
2023-求平均值
二维数组的基本使用
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 60, M = 10;
double s[N][M], cnt;
void init(int n, int m)
{
for (int i = 1; i <= N; i ++ )
for (int j = 1; j <= M; j ++ )
s[i][j] = 0;
cnt = 0;
}
int main()
{
int n, m;
while(cin >> n >> m)
{
init(n, m);
for (int i = 1; i <= n; i ++ )
{
double sum = 0;
for (int j = 1; j <= m; j ++ )
{
double k;
cin >> k;
s[i][j] = k;
s[n+1][j] += k; // 第n+1行记录每科成绩平均分
sum += k;
}
s[i][m+1] = sum / m; // 第m+1列记录学生平均分
}
for (int i = 1; i <= m; i ++ ) s[n+1][i] /= n;
for (int i = 1; i <= n; i ++ ) printf("%.2f ",s[i][m+1]);//学生的平均分
puts("");
for (int i = 1; i <= m; i ++ ) printf("%.2f ",s[n+1][i]);//课程分
puts("");
for (int i = 1; i <= n; i ++ )
{
int w = 0;
for (int j = 1; j <= m; j ++ )
{
if(s[i][j] >= s[n+1][j]) w++;
}
if(w == m) cnt++;
}
cout << cnt << endl;
puts("");
}
return 0;
}
2024-C语言合法标识符
这里强调字符串输入格式
scanf("%d%",&n); getchar(); //等价于scanf("%d%*c",&n); 缓冲区为 3\n 二者都是拿走\n %*c 的标准用法是什么。它的意义何在? 我所知道的是它经常出现在例如 cscanf("%s%*c",&a);语句中。 /* 你的例子中的%*c的作用是读入'\n',即回车符,否则后面读入的将是'\n'。 "*"表示该输入项读入后不赋予任何变量,即跳过该输入值。 */
合法标识符定义
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
static int n;
static char s[60];
int getlen (char *str)
{
int cnt;
for (int i = 0; str[i] != '\0' ; ++i)
{
cnt++;
}
return cnt;
}
int process (char *str)
{
if (str[0] - 'a' >= 0 && 'z'-str[0] >=0) ;
else if (str[0] - 'A' >= 0 && 'Z'-str[0] >=0) ;
else if (str[0] == '_') ;
else return 0;
if (str[0]-'0' )
for (int i = 1; str[i] != '\0' ; ++i) {
if (str[i] - 'a' >= 0 && 'z'-str[i] >=0) continue;
else if (str[i] - 'A' >= 0 && 'Z'-str[i] >=0) continue;
else if (str[i] - '0' >= 0 && '9'-str[i] >=0) continue;
else if (str[i] == '_') continue;
else return 0;
}
return 1;
}
int main(void)
{
scanf("%d%",&n);
getchar(); //等价于scanf("%d%*c",&n); 缓冲区为 3\n 二者都是拿走\n
while(n--)
{
cin.getline(s, 60);
//printf("%s\n", s);
process(s) ? printf("yes\n") : printf("no\n");
}
return 0;
}
2025-查找最大元素
主要是解决字符串输入问题
关于使用 gets() 函数需要注意:使用 gets() 时,系统会将最后“敲”的换行符从缓冲区中取出来,然后丢弃,所以缓冲区中不会遗留换行符。这就意味着,如果前面使用过 gets(),而后面又要从键盘给字符变量赋值的话就不需要吸收回车清空缓冲区了,因为缓冲区的回车已经被 gets() 取出来扔掉了。
原文链接:gets函数,C语言gets函数详解_gets()的功能-优快云博客
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
static char s[120];
static char m;
int main(void)
{
while(gets(s))
{
m = 'a';
for (int i = 0; s[i] != '\0'; ++i) {
if (s[i] > m) m = s[i];
}
for (int i = 0; s[i] != '\0'; ++i) {
if (s[i] == m) printf("%c(max)",s[i]);
else printf("%c",s[i]);
}
printf("\n");
}
return 0;
}
2028-最小公倍数(最大公约数变体)
a和b的最小公倍数:a * b / gcd(a,b)
故三个数的最小公倍数:先求前两个的最小公倍数c,再拿c和第三个数求最小公倍数。n个以此类推。
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long LL;
LL gcd (LL a, LL b)
{
return b ? gcd(b, a % b) : a;
}
int main()
{
LL n, a, b, c;
while (cin >> n)
{
if(n == 1){
cin >> a;
cout << a << endl;
}
else {
cin >> a >> b;
LL pre = a * b / gcd(a, b);
for (int i = 3; i <= n; i ++ )
{
cin >> c;
pre = pre * c / gcd(pre, c);
}
cout << pre << endl;
}
}
return 0;
}
2030-汉字统计
清楚汉字编码的特点:汉字码是小于0。并且一个汉字占两个字节(每一个字节均小于0)。
注意:getline(cin,s)对应头文件#include<string>
#include <iostream>
#include <cstring>
#include <algorithm>
#include <cstdio>
#include <string>
using namespace std;
int main()
{
int n;
cin >> n;
getchar();
while (n -- )
{
string s;
getline(cin,s);
int cnt = 0;
for (int i = 0; i < s.size(); i++ )
if(s[i] < 0) cnt++;
cout << cnt/2 << endl;
}
return 0;
}
2031-进制转换
进制转换模版
#include <iostream>
#include <cstring>
#include <string>
#include <algorithm>
using namespace std;
char itoc (int x)
{
if(x <= 9) return x + '0';
return x + 'A' - 10;
}
int main()
{
int n, b, abs_n;
while(cin >> n >> b)
{
abs_n = n < 0 ? -n : n;
string res;
while(abs_n) res += itoc(abs_n % b), abs_n /= b;
if(n < 0) res += "-";
reverse(res.begin(), res.end());
cout << res << endl;
}
return 0;
}
2034-人见人爱A-B
set容器的应用
#include <iostream>
#include <cstring>
#include <algorithm>
#include <set>
using namespace std;
int n, m;
int main()
{
while (cin >> n >> m)
{
set<int> a;
if(n==0 && m==0) break;
for (int i = 1; i <= n; i ++ )
{
int num;
cin >> num;
a.insert(num);
}
for (int i = 1; i <= m; i ++ )
{
int num;
cin >> num;
if(a.find(num) != a.end()) a.erase(num);
}
if (!a.size()) cout << "NULL" << endl;
else {
for (auto w : a) cout << w << " ";
puts("");
}
}
return 0;
}
2036-改革春风吹满地
2037-今年暑假不AC
2040-亲和数
数学:公约数问题
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
int get_gys(int k)
{
int sum = 0;
for (int i = 1; i <= k/i; i ++ )
{
if(k % i == 0)
{
sum += i;
if(i != k/i) sum += k/i;
}
}
return sum;
}
int main()
{
int n;
cin >> n;
while (n -- )
{
int a, b;
cin >> a >> b;
if(get_gys(a) == get_gys(b)) cout << "YES" << endl;
else cout << "NO" << endl;
}
return 0;
}
2041-超级楼梯
递推题
由题目可知,每次只能走一级或两级。 因此从第一级走上第二级只能走一步,只有1种走法。 从第一级走上第三级,可以从第一级直接走两步,也可以从第二级走一步。有2种走法 走上第n级,可以从第n-1级走一步上来,也可以从第n-2级走两步上来。 即: f(2) = 1 f(3) = 2 f(n) = f(n-1) + f(n-2) (n > 3) 是一个斐波那契函数。
#include <iostream>
#include <cstdio>
using namespace std;
static int n;
static long long arr[41];
int m;
int main(void)
{
arr[1] = 1;
arr[2] = 1;
scanf("%d",&n);
for (int i = 3; i <= 40; ++i) {
arr[i] = arr[i-1] + arr[i-2];
}
while(n--)
{
scanf("%d",&m);
if (m <=2) {
if (m==1) printf("%d\n",0);
else printf("%d\n",1);
continue;
}
printf("%d\n",arr[m]);
}
return 0;
}
2044-小蜜蜂
递推题
其中从3到6等价于从1到4
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
static int n;
static long long arr[60];
int a,b;
int main(void)
{
arr[2] = 1;
arr[3] = 2;
for (int i = 4; i < 51; ++i) {
arr[i] = arr[i-1] + arr[i-2];
}
scanf("%d",&n);
while(n--)
{
scanf("%d%d",&a,&b);
int d = b-a;
printf("%lld\n",arr[1+d]);
}
return 0;
}
2045-RPG难题
递推题
其实这道题的解法就是站在涂色后的最后一块,思考前一块是怎么涂色的就可以了,比如 如果最后一块的前一块是与第一块颜色不同的情况,则最后一块只有一种颜色可以涂,其方法的数目等于f(n-1),而当最后一块前面一块的颜色与第一块相同时,则倒数第三块一定与第一块的颜色不同,则涂到倒数第三块有f(n-2)方法,到倒数第二块有f(n-2)种方法,最后一块则有 f(n-2)2种方法,由此可以的出递推的关系式 f(n)=f(n-1)+2 * f(n-2); 题目中给出的范围不大,可以先采取打表的方法给出所有的结果,再输出即可。
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 51;
long long f[N];
int main()
{
int n;
f[1] = 3, f[2] = 6, f[3] = 6;
for (int i = 4; i < N; i ++ )
f[i] = f[i-1] + f[i-2] * 2;
while (cin >> n)
{
cout << f[n] << endl;
}
return 0;
}
2046-骨骼铺方格
递推题
从图中也可以观察出来,第N张牌的排列可以又N-1张牌的排列再在末尾加上一张竖的牌。这样依然合法。 也可以在N-2张合法排列的牌后面加上两张横着放的牌(如果竖着放就和上面一种重复了)。
所以f(n) = f(n-1) + f(n-2) 即又是一个斐波那契数列。
#include <cstdio>
using namespace std;
static int n;
static long long arr[51];
int main(void)
{
arr[1] = 1;
arr[2] = 2;
arr[3] = 3;
for (int i = 4; i < 51; ++i) {
arr[i] = arr[i-1] + arr[i-2];
}
while(scanf("%d",&n) != EOF)
{
printf("%lld\n",arr[n]);
}
return 0;
}
2047-EOF
递归题
分为两种情况 当第n个是“O”时,依据限制条件,那么第n-1个不能为“O”,那n-1不为“O”就有两种情况了,即为“E”或者“F”,所以这种情况有f(n-2)2个 当第n个不为“O”时,与第一步相同,也有两种情况,即为“E”或者“F”,所以这种情况有f(n-1)2个. 递推公式:f(n)=f(n-2) * 2+f(n-1) * 2
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 41;
long long f[N];
int main()
{
int n;
f[1] = 3, f[2] = 8;
for (int i = 3; i < N; i ++ )
f[i] = f[i-1]* 2 + f[i-2] * 2;
while (cin >> n)
{
cout << f[n] << endl;
}
return 0;
}
原文链接:杭电ACM 2047 - 阿牛的EOF牛肉串(解题思路与详细分析)_阿牛的牛肉串题解-优快云博客
2051-进制转换
十进制转二进制
模版题
#include <iostream>
#include <string>
#include <algorithm>
using namespace std;
char itoc (int x)
{
if(x <= 9) return x + '0';
else return 'A' + x - 10;
}
int main()
{
int n;
while (cin >> n)
{
string s;
while(n) s += itoc(n % 2), n /= 2;
reverse(s.begin(), s.end());
cout << s << endl;
}
return 0;
}
2057-A+B again
笨比做法:转十进制再转十六进制
#include <iostream>
#include <string>
#include <algorithm>
using namespace std;
string s[100];
long long ctoi (char c)
{
if(c >= '0' && c <= '9') return c - '0';
else if(c >= 'A' && c <= 'Z') return c - 'A' + 10;
else return c - 'a' + 10;
}
char itoc (long long x)
{
if(x <= 9 && x >= 0) return x + '0';
else return x - 10 + 'A';
}
int main()
{
string s1, s2;
while (cin >> s1 >> s2 )
{
long long len1 = s1.size(), len2 = s2.size();
long long i1 = 0, i2 = 0;
if(s1[0] == '+' || s1[0] == '-') i1++;
if(s2[0] == '+' || s2[0] == '-') i2++;
long long n1 = 0, n2 = 0;
for (int i = i1; i < len1 ; i ++ ) n1 = n1 * 16 + ctoi(s1[i]);
for (int i = i2; i < len2 ; i ++ ) n2 = n2 * 16 + ctoi(s2[i]);
long long ans = 0;
if(s1[0] != '-' && s2[0] != '-') ans = n1 + n2;
if(s1[0] != '-' && s2[0] == '-') ans = n1 - n2;
if(s1[0] == '-' && s2[0] != '-') ans = -n1 + n2;
if(s1[0] == '-' && s2[0] == '-') ans = -n1 - n2;
if (ans == 0) cout << 0 << endl;
else
{
if(ans < 0)
{
cout << "-";
ans = -ans;
}
string s;
while(ans) s += itoc(ans % 16), ans /= 16;
reverse(s.begin(), s.end());
cout << s << endl;
}
}
return 0;
}
2064-汉诺塔3
递推式,把前n-1层看成一个整体移动,故f[n] = 3 * f[n-1] + 2;
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 36;
long long hnt[N];
void init_hnt()
{
hnt[1] = 2;
for (int i = 2; i <= 35; i ++ )
{
hnt[i] = 3*hnt[i-1] + 2;
}
}
int main()
{
int n;
init_hnt();
while(cin >> n)
{
cout << hnt[n] << endl;
}
return 0;
}
2066-一个人的旅行
Dijkstra:这里可以把人看做0号顶点,到相邻城市的距离为0
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 1010;
int g[N][N];
int dist[N], st[N], city[N], aim[N];
int a, b, val, t, s, d, n;
void init()
{
memset(g, 0x3f, sizeof g);
memset(dist, 0x3f, sizeof dist);
memset(st, 0, sizeof st);
}
void dijkstra() //从k到n的最短距离, 其中1 <= k <=n .
{
//dist[k] = 0;
for (int i = 0; i < n; i ++ )
{
int t = -1;
for (int j = 1; j <= n; j ++ )
if(!st[j] && (t == - 1 || dist[t] > dist[j]) )
t = j;
st[t] = 1;
for (int j = 1; j <= n; j ++ )
dist[j] = min(dist[j], dist[t] + g[t][j]);
}
}
int main()
{
while (cin >> t >> s >> d)
{
init();
while (t -- )
{
cin >> a >> b >> val;
if(a != b)
{
g[a][b] = g[b][a] = min(g[a][b], val);
n = max(n, b);
n = max(n, a);
}
}
int k;
for (int i = 1; i <= s; i++)
{
cin >> k;
dist[k] = 0;
g[0][k] = g[k][0] = 0;
}
for (int i = 1; i <= d; i++) cin >> aim[i];
dijkstra();
int ans = 1e9;
for (int j = 1; j <= d; j ++ )
ans = min(ans, dist[aim[j]]);
cout << ans << endl;
}
return 0;
}
2067-小兔的棋盘
二维数组的递推式(二维超级楼梯):要使得路径最小,每次仅往右或往下(好兔不走回头路)
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 36;
long long dp[N][N];
int k, cnt;
void init_dp(int n)
{
for (int i = 0; i <= n; i ++ ) dp[0][i] = 1;
for (int i = 1; i <= n; i ++ )
{
for (int j = i; j <= n; j ++ )
{
if(i == j) dp[i][j] = dp[i-1][j];
else dp[i][j] = dp[i][j-1] + dp[i-1][j];
}
}
}
int main()
{
init_dp(35);
while(cin >> k)
{
if(k==-1) break;
printf("%d %d %lld\n",++cnt,k,dp[k][k] << 1);
}
return 0;
}
2072-单词数
利用set数据不重复的特性。注意:要考虑多个空格的边界条件
#include <iostream>
#include <string>
#include <algorithm>
#include <set>
using namespace std;
int main()
{
set<string> v;
string s, word;
while(getline(cin,s))
{
if(s == "#") return 0;
v.clear();
int len = s.size();
for (int i = 0; i < len; i ++ )
{
if(s[i] == ' ')
{
if(word.size()) {
v.insert(word);
word = "";
}
}
else word += s[i];
}
if(word.size()) {
v.insert(word);
word = "";
}
cout << v.size() << endl;
}
return 0;
}
2074-叠框
每次以上一行为基准翻转数组,然后对称输出
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 81;
char g[N][N];
int n;
char zx, ww;
void write(int x, int a, int b) //写x行第a列到第b列
{
char c;
c = g[x-1][a] == zx ? ww : zx;
for (int i = 1; i < a; i ++ ) g[x][i] = g[x-1][i];
for (int i = a; i <= b; i ++ ) {
g[x][i] = c;
}
for (int i = b+1; i <= n; i ++ ) g[x][i] = g[x-1][i];
}
int main()
{
while(cin >> n >> zx >> ww)
{
if(n == 1)
{
cout << zx << endl;
puts("");
}
else {
int mid = (n + 1) >> 1;
char first;
first = mid % 2 == 0 ? ww : zx;
for (int i = 1; i <= n; i ++ )
g[1][i] = first;
for (int i = 2; i <= mid; i ++ )
write(i, i, n-i+1);
g[1][1] = ' ';
g[1][n] = ' ';
for (int i = 1; i <= mid; i ++ )
{
for (int j = 1; j <= n; j ++ )
{
cout <<g[i][j] << "";
}
cout << endl;
}
//对称输出
for (int i = mid-1; i >= 1; i -- )
{
for (int j = 1; j <= n; j ++ )
{
cout <<g[i][j] << "";
}
cout << endl;
}
puts("");
}
}
return 0;
}
2076-夹角计算1
推导数学公式
#include <iostream>
#include <cstring>
#include <algorithm>
#include <string>
using namespace std;
const int N = 510;
double hour_add = 0, min_add = 0, hour_angle = 0, min_angle = 0, d = 0;
// 时针30度一格, 分针6度一格
// 时钟一格 秒钟3600转
// 分钟一格秒钟60
int main()
{
int n;
double hour, mi, sec;
cin >> n;
while (n -- )
{
hour_angle = 0, min_angle = 0, d = 0;
cin >> hour >> mi >> sec;
if(hour >= 12) hour = hour - 12;
//秒钟转 从而分钟转 从而时钟转
hour_angle = hour * 30 + (mi * 60 + sec) / 3600* 30; //时钟一格 秒钟3600
min_angle = mi * 6 + sec / 60 * 6;//分钟一格 秒钟60
d = hour_angle - min_angle;
d = abs(d);
if(d > 180) d = 360-d;
cout << (int)d << endl;
}
return 0;
}
2077-汉诺塔4
递推式:先求出到相邻杆子的最小移动次数
#include <iostream>
#include <cstring>
#include <algorithm>
typedef long long LL;
using namespace std;
const int N = 21;
LL dp[N]; //把n个移动到相邻盘
void init()
{
dp[1] = 1;
dp[2] = 4;
for (int i = 3; i < N; i ++ )
dp[i] = dp[i-1]*3 + 1;
}
int main()
{
init();
int n, k;
cin >> n;
while (n -- )
{
cin >> k;
cout << dp[k-1]*2 + 2 << endl;
}
return 0;
}
2079-选课时间
DFS排列组合(去重+剪枝)
#include <iostream>
#include <cstring>
#include <algorithm>
#include <queue>
using namespace std;
int s[9], cnt;
void init()
{
for (int i = 1; i <= 8; i ++ ) s[i] = 0;
cnt = 0;
}
void dfs(int x,int idx)
{
if(!x) {
cnt++;
return;
}
for (int i = idx; i <= 8; i ++ )
{
if(!s[i]) continue;
if(x-i < 0) continue;
s[i]--;
dfs(x-i,i);
s[i]++;
}
}
int main()
{
int t;
cin >> t;
while (t--)
{
init();
int n, k;
scanf("%d%d", &n, &k);
for (int i = 1; i <= k; i ++ )
{
int a, b;
scanf("%d%d", &a, &b);
s[a] = b;
}
for (int i = 1; i <= 8; i ++ )
{
if(!s[i]) continue;
if(n-i < 0) continue;
s[i]--;
dfs(n-i,i);
s[i]++;
}
cout << cnt << endl;
}
return 0;
}
2080-夹角计算2
atan求角度,注意对 正负四象限 两种情况区分讨论,本题以x正方向为基准
#include <iostream>
#include <cstring>
#include <algorithm>
#include <cmath>
using namespace std;
#define PII 3.1415926535898
double x_1, y_1, x_2, y_2, d;
// 时针30度一格, 分针6度一格
// 时钟一格 秒钟3600转
// 分钟一格秒钟60
double get_angle(double x, double y)
{
if(x == 0) return y > 0 ? 90: 270;
else if(y == 0) return x > 0 ? 0: 180;
double k = atan(y / x) / PII * 180;
k = abs(k);
if(x > 0 && y >= 0) return k;
else if(x < 0 && y <= 0) return k + 180;
else if(x > 0 && y <= 0) return 360 - k;
else if(x < 0 && y >= 0) return 180 - k;
}
int main()
{
int n;
cin >> n;
while (n -- )
{
double angle1, angle2;
cin >> x_1 >> y_1 >> x_2 >> y_2;
angle1 = get_angle(x_1,y_1);
angle2 = get_angle(x_2,y_2);
double d = abs(angle1-angle2);
if(d > 180) d -= 180;
printf("%.2f \n",d);
}
return 0;
}
2081-手机短号
水题,字符串输出
#include <iostream>
#include <cstring>
#include <algorithm>
#include <string>
using namespace std;
int main()
{
int n;
cin >> n;
getchar();
for (int i = 1; i <= n; i ++ )
{
string s;
getline(cin, s);
int len = s.size();
cout << '6';
for (int i = 6; i < len; i ++ )
cout << s[i];
puts("");
}
return 0;
}
2082-找单词
多重背包问题,注意:边界条件是f[i][0] = 1;
f[i][j]表示前i个字母组成价值为j的最大单词数量
j = 0 时,意味着只有一种情况
可以优化为滚动数组
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 110;
int v[N], w[N], s[N];
int f[N][N];
int main()
{
int n, m;
cin >> n >> m;
for (int i = 1; i <= n; i ++ ) cin >> v[i] >> w[i] >> s[i];
for (int i = 1; i <= n; i ++ )
{
for (int j = 0; j <= m; j ++ )
{
f[i][j] = f[i-1][j];
for (int k = 1; k <= s[i]; k ++ )
if(j >= k * v[i]) f[i][j] = max(f[i][j], f[i-1][j - k * v[i]] + k * w[i]);
}
}
cout << f[n][m];
return 0;
}
2083-简易版最短距离
贪心:站在中间(左右房子数量相同),每次路程即为两端点最短距离(双指针)
#include <iostream>
#include <cstring>
#include <algorithm>
#include <string>
using namespace std;
const int N = 510;
int f[N], d;
int main()
{
int m, n;
cin >> m;
for (int i = 1; i <= m; i ++ )
{
cin >> n;
d = 0;
for (int j = 1; j <= n; j ++ ) cin >> f[j];
sort(f+1,f+n+1);
int a, b;
for (a = 1, b = n; a < b; a++, b--)
d += f[b] - f[a];
cout << d << endl;
}
return 0;
}
2084 -数塔
最大值DP问题
自上而下,保存每一个结点的路径最大值
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 110;
int dp[N][N];
void init()
{
for (int i = 1; i <= N; i ++ )
for (int j = 1; j <= i; j ++ )
dp[i][j] = 0;
}
int main()
{
int c, n;
cin >> c;
while (c --)
{
cin >> n;
int res = 0;
for (int i = 1; i <= n; i ++ ) //输入数组
for (int j = 1; j <= i; j ++ )
cin >> dp[i][j];
//计算第一列结点最大值
for (int i = 2; i <= n; i ++) dp[i][1] += dp[i-1][1];
//计算其余结点最大值
for (int i = 2; i <= n; i ++ )
for (int j = 2; j <= i; j ++ )
dp[i][j] += max(dp[i-1][j],dp[i-1][j-1]);
//找到叶子结点最大值
for (int i = 1; i <= n; i ++)
res = max(res,dp[n][i]);
cout << res << endl;
}
return 0;
}
2085-核反应堆
观察规律,找到公式即可
#include <iostream>
using namespace std;
bool is_Prime(int a)
{
if (a < 2) return false;
for (int i = 2; i <= a/i; i++)
if (a % i == 0) return false;
return true;
}
int main()
{
int n;
while(scanf("%d",&n) != EOF)
{
if (n == -1) break;
long long h_old = 1, l_old = 0;
while(n--)
{
long long h_add_h = 3*h_old;
long long h_add_l = h_old;
long long l_add_h = 2*l_old;
long long l_add_l = l_old;
h_old = h_add_h + l_add_h;
l_old = h_add_l + l_add_l;
}
cout << h_old << ", " << l_old << endl;
}
return 0;
}
2087-剪花布条
本题数据量小,可直接枚举n²,若数据量大,考虑KMP
#include <iostream>
#include <string>
#include <algorithm>
using namespace std;
string a, b;
int len1 ,len2;
bool get_num (int idx)
{
for (int i = idx, j = 0; i < len1 && j < len2; i++, j++ )
{
if(a[i] != b[j]) return false;
}
return true;
}
int main()
{
while (cin >> a)
{
int cnt = 0;
if(a == "#") return 0;
cin >> b;
len1 = a.size();
len2 = b.size();
for (int i = 0; i <= len1-len2; )
{
if(get_num(i))
{
cnt++;
i += len2;
} else i++;
}
cout << cnt << endl;
}
return 0;
}
2089-不要62
把数字转为字符串,并判断是否符合题意
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 1e6 + 10;
int f[N];
bool is_62 (int x)
{
string s;
char a;
while (x) //将int x 转为 string x(倒序)
{
a = x % 10 + '0';
s += a;
x /= 10;
}
int len = s.size();
for (int i = 0; i < len - 1; i++)
{
if(s[i] == '2' && s[i+1] == '6') return true;
if(s[i] == '4') return true;
}
if(s[len-1] == '4') return true;
return false;
}
int main()
{
int n, m, cnt = 0;
for (int i = 1; i <= 1e6; i ++ )
if(!is_62(i))
{
f[i] = ++cnt;
} else f[i] = f[i-1];
while (cin >> n >> m)
{
if(n == 0 && m == 0) return 0;
int ans = f[m] - f[n-1];
printf("%d\n",ans);
}
return 0;
}
2091-空三角形
观察位置规律,写出公式即可
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
int main()
{
char op;
int n;
while(cin >> op)
{
if(op == '@') break;
cin >> n;
if(n == 1) {
cout << op << endl;
puts("");
}
else {
for(int i = 1; i < n; i++)
{
int k = 2*n-1;
int mid = k / 2 + 1;
for (int j = 1; j <= k; j++)
{
if((j == mid - i + 1) || (j == mid + i - 1)) cout << op;
else cout << " ";
}
cout << endl;
}
for (int i = 1; i <= (2*n-1); i ++ ) cout << op;
puts("");
}
puts("");
}
return 0;
}
2093-考试排名
结构体/输入/输出/重载比较运算
#include <iostream>
#include <string>
#include <algorithm>
#include <vector>
#include <iomanip>
using namespace std;
typedef struct Acm
{
string name = "";
int ac = 0;
int time = 0;
} Acmer;
bool cmp (Acmer a, Acmer b)
{
if(a.ac == b.ac) return a.time < b.time;
else return a.ac > b.ac;
}
int main()
{
vector<Acmer> v;
string s;
int n, m;
cin >> n >> m;
while(cin >> s)
{
Acmer acm;
acm.name = s;
int sorce, worse;
for (int i = 1; i <= n; i ++ )
{
cin >> sorce;
if (sorce <= 0) continue;
acm.ac++;
acm.time += sorce;
if(getchar() == '(')
{
cin >> worse;
acm.time += worse * m;
getchar();
}
}
v.push_back(acm);
}
sort(v.begin(), v.end(), cmp);
for (auto w : v)
cout << left << setw(10) << w.name << " "
<< right << setw(2) << w.ac <<" "
<< right << setw(4) << w.time <<endl;
return 0;
}
2092-整数解
数学问题
化简得:xx - nx + m == 0 ,开口向上的抛物线,从对称轴往右侧遍历直到左式不小于0,判断其中是否有整数解
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
int n, m;
bool is_int (int x)
{
while (x*x - n*x + m < 0)
{
x++;
}
return x * (n - x) == m;
}
int main()
{
while (cin >> n >> m)
{
if(n == 0 && m == 0) return 0;
if (n * n - 4 * m < 0) cout << "No" << endl;
else {
int mid = n / 2; //对称轴
if(is_int(mid)) cout << "Yes" << endl;
else cout << "No" << endl;
}
}
return 0;
}
2094-产生冠军
输入样例等价为一个有向图,当仅有一个结点入度为0时,产生冠军
#include <iostream>
#include <cstring>
#include <algorithm>
#include <map>
#include <string>
using namespace std;
int main()
{
int n;
string name1, name2;
while(scanf("%d", &n), n)
{
map<string, int> v;
while (n -- )
{
cin >> name1 >> name2;
if(v.find(name1) == v.end()) v[name1] = 0;
v[name2] ++;
}
int cnt = 0;
for (auto w : v)
{
if(w.second == 0) cnt++;
if(cnt > 1) break;
}
if(cnt == 1) cout << "Yes" << endl;
else cout << "No" << endl;
}
return 0;
}
2095-find presen
map容器的应用
#include <iostream>
#include <cstring>
#include <algorithm>
#include <map>
using namespace std;
int main()
{
int n, k;
while (scanf("%d",&n),n)
{
map<int, int> fd;
while (n -- ) {
scanf("%d", &k);
fd[k]++;
}
for (auto w : fd)
{
if(w.second == 1)
{
printf("%d\n",w.first);
break;
}
}
}
return 0;
}
2097-Sky数
进制转换问题
#include <iostream>
#include <cstring>
#include <string>
#include <algorithm>
using namespace std;
int ctoi (char c)
{
if(c <= '9') return c - '0';
if(c <= 'Z') return c - 'A' + 10;
return c - 'a' + 10;
}
char itoc (int x)
{
if(x <= 9) return '0' + x;
return x - 10 + 'A';
}
int sum_10 (int x)
{
int res = 0;
while (x) res += x % 10, x /= 10;
return res;
}
int sum_16 (string s)
{
int res = 0;
for (auto w : s)
{
if(w <= '9') res += w - '0';
else res += w - 'A' + 10;
}
return res;
}
int sum_12 (string s)
{
int res = 0;
int len = s.size();
for (int i = 0; i < len; i++)
{
char w = s[i];
if(w <= '9') res += w - '0';
else res += (int)w - 'A' + 10;
}
return res;
}
// 把十进制数n 转x进制
string toX (int num, int x)
{
string s;
while(num) s += itoc(num % x), num /= x;
reverse(s.begin(), s.end());
return s;
}
int main()
{
int n;
while (scanf("%d",&n),n)
{
int sum = sum_10(n);
string s1, s2;
s1 = toX(n, 16);
s2 = toX(n, 12);
int sum1, sum2;
sum1 = sum_16(s1);
sum2 = sum_12(s2);
if(sum == sum1 && sum == sum2)
printf("%d is a Sky Number.\n",n);
else printf("%d is not a Sky Number.\n",n);
}
return 0;
}
2099-整数的尾除
分析规律:补上 余数与除数的差额 ,即可得到当前最小可被整除的数
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 41;
long long f[N];
int main()
{
char c;
int a, b;
while (cin >> a >> b)
{
if (a == 0 && b == 0) break;
a = a * 100;
int k = a % b;
if(k != 0)
{
a += b - k;
k = a % 100;
}
while(k < 100)
{
printf("%02d ",k);
k += b;
}
puts("");
}
return 0;
}