“亚信科技杯”南邮第七届大学生程序设计竞赛之网络预赛
比赛链接http://acm.njupt.edu.cn/acmhome/contest.do?&method=contestDetail&contestId=215 FFF
FFF
时间限制(普通/Java) : 1000 MS/ 3000 MS 运行内存限制 : 65536 KByte
总提交 : 130 测试通过 : 9
题目描述
FFF团,一个异端审判组织,团员活跃在各个角落,每当烧烤节来临的时候,我们都能听到他们传播的那熟悉的旋律:
烧啊~烧啊~烧啊烧啊烧~ (请自行脑补《当》)
FFF团成员自带这样一个属性:凭空变出火把与汽油,两者配合起来才能让FFF之火duang的一下烧起来,但是不同的火把与不同的汽油配合产生的火焰是不同的,现在有n种火把与n种汽油,已知每一种火把与每一种汽油配合时产生的火焰的旺盛程度,现在求怎样使得火把与汽油一一配对,产生最旺盛的火焰。
输入
第一行为一个整数T,表示有T组数据
每组数据第一行为一个正整数n(2≤n≤30)
第二行开始一共有n行,每行为n个正整数,第i行第j个数表示第i种火把与第j种汽油配合的火焰的旺盛程度。(0<a[i][j]≤10000)
输出
每组数据输出一个整数,表示最大的火焰旺盛程度
样例输入
2
3
5 2 6
6 7 9
7 4 1
4
8 5 2 8
5 8 2 1
9 6 3 7
7 5 8 1
样例输出
20
33
题目来源
kojimai
题目分析:开始没多久就被秒掉的题。。。果然是个裸模板,二分图带权最大匹配,套一个km的板子就行了,km算法就不在这说了
#include <cstdio> #include <cstring> int const MAX = 50; int const INF = 0x3fffffff; int n, nx, ny; int link[MAX], lx[MAX], ly[MAX], slack[MAX]; int visx[MAX], visy[MAX], w[MAX][MAX]; int DFS(int x) { visx[x] = 1; for(int y = 1; y <= ny; y++) { if(visy[y]) continue; int t = lx[x] + ly[y] - w[x][y]; if(t == 0) { visy[y] = 1; if(link[y] == -1 || DFS(link[y])) { link[y] = x; return 1; } } else if(slack[y] > t) slack[y] = t; } return 0; } int KM() { memset(link, -1, sizeof(link)); memset(ly, 0, sizeof(ly)); for(int i = 1; i <= nx; i++) { lx[i] = -INF; for(int j = 1; j <= ny; j++) if(w[i][j] > lx[i]) lx[i] = w[i][j]; } for(int x = 1; x <= nx; x ++) { for(int i = 1; i <= ny; i ++) slack[i] = INF; while(true) { memset(visx, 0, sizeof(visx)); memset(visy, 0, sizeof(visy)); if(DFS(x)) break; int d = INF; for(int i = 1; i <= ny; i++) if(!visy[i] && d > slack[i]) d = slack[i]; for(int i = 1; i <= nx; i++) if(visx[i]) lx[i] -= d; for(int i = 1; i <= ny; i++) if(visy[i]) ly[i] += d; else slack[i] -= d; } } int res = 0; for(int i = 1; i <= ny; i++) if(link[i] > -1) res += w[link[i]][i]; return res; } int main () { int T; scanf("%d", &T); while(T--) { scanf("%d", &n); nx = ny = n; for(int i = 1; i <= n; i++) for(int j = 1; j <= n; j++) scanf("%d", &w[i][j]); int ans = KM(); printf("%d\n", ans); } }
pdf的旅游
时间限制(普通/Java) : 1000 MS/ 3000 MS 运行内存限制 : 65536 KByte
总提交 : 100 测试通过 : 21
题目描述
a协有一位pdf是一位旅(作)游(死)爱好者,曾经在出去比赛之后拐带学弟翘课一周,四处旅游。
最近pdf又突发奇想,想再出去旅游一次。出去旅游之前当然要好好计划一番。Pdf给自己想去的地方并给它们编好了号(起点为1)。为了不跟自己过不去,pdf提前找出哪些地点存在交通方便的路径,而且只会走这些路径。
为了旅途乐趣的最大化,pdf希望每个地点都到访过的同时,又保证来去都不会走重复的路,而且最终还要回到起点。问想要达到上述要求,pdf应该怎么样安排地点的访问顺序。
输入
第一行一个整数t,表示数据组数。
每组数据的第一行两个整数n,m分别表示地点数和路径数。(2≤n≤10,n≤m≤n(n-1)/2)
接下来的m行每行两个整数x,y 表示x,y之间交通方便。(保证两点之间只会有一条路)(1≤x,y≤n)
输出
每组数据输出一行,从起点开始的游览顺序。以空格分隔开。如果存在多解,则输出字典序最小的路径。(除起点外每个点只能访问一次)
样例输入
2
4 4
1 3
2 3
2 4
1 4
5 7
1 4
1 5
4 2
5 3
3 2
5 4
2 1
样例输出
1 3 2 4 1
1 2 3 5 4 1
题目来源
kojimai
题目分析:第一眼看以为是欧拉回路,拍完发现并不是,其实就是一道搜索题,其实因为n只有10,暴力就能过了,枚举全排列,模拟一下
#include <cstdio> #include <cstring> #include <algorithm> using namespace std; int flag[20][20]; int p[11]; int main() { int T; scanf("%d", &T); while(T--) { memset(flag, 0, sizeof(flag)); int n, m; scanf("%d %d", &n, &m); for(int i = 0; i < m; i++) { int a, b; scanf("%d %d", &a, &b); flag[a][b] = 1; flag[b][a] = 1; } for(int i = 0; i < n; i++) p[i] = i + 1; p[n] = 1; do { bool f = true, f2 = false; for(int i = 0; i < n; i++) { if(i == n - 1 && !flag[p[i]][1]) { f = false; break; } if(i != n - 1 && !flag[p[i]][p[i + 1]] && !flag[p[i + 1]][p[i]]) { f = false; break; } } if(f) break; }while(next_permutation(p, p + n)); for(int i = 0; i < n; i++) printf("%d ", p[i]); printf("1\n"); } }
特技的幂
时间限制(普通/Java) : 1000 MS/ 3000 MS 运行内存限制 : 65536 KByte
总提交 : 481 测试通过 : 103
题目描述
幂运算是常见的数学运算之一,其原理是用同一个数相乘多次,但是有的时候当幂指数特别大的时候,这样的运算就太浪费时间。请大家学会在幂中加特技,让幂运算的效率提高到可以接受的程度。
输入
第一个行一个整数T,表示有T组数据
每组数据,输入x,y 求x的y次幂 (2≤ x ,y≤10^9)
输出
每组数据输出一个整数,表示幂运算对1000000007取模后的结果
样例输入
2
2 4
2 100000000
样例输出
16
494499948
题目来源
kojimai
题目分析:这。。。
#include <cstdio> #define ll long long int const MOD = 1e9 + 7; ll quick_pow(ll a, ll b,ll m) { ll d = 1, t = a; while(b > 0) { if(b % 2) d = (d * t)%m; b /= 2; t = (t * t) % m; } return d; } int main() { int T; scanf("%d", &T); while(T--) { ll a, b; scanf("%I64d %I64d", &a, &b); printf("%I64d\n", quick_pow(a, b, MOD)); } }
天神小学
时间限制(普通/Java) : 1000 MS/ 3000 MS 运行内存限制 : 65536 KByte
总提交 : 145 测试通过 : 50
题目描述
《corpse party:blood drive》中有这么一段,班长筱崎亚由美拿到六鬼门的晶石,导致了涅?的暴走,天小的崩溃,靠着幸子的力量才逃出了天小。(剧情什么的不重要)
现在我们假设没有幸子,班长需要靠自己的力量逃出天神小学。可以把天神小学看作是一个二维的迷宫,每一秒都只能从当前位置走到上下左右四个相邻的格子里,因为天小一直在崩溃,所以有很多点是无法行走的。问班长能不能在天小完全崩溃,即t秒内逃出天神小学。
输入
第一行一个整数T,表示数据组数
每组数据第一行输入3个整数n,m,t分别表示迷宫的行数,列数,以及距离天小崩溃剩余的时间。(3≤n,m≤20,t≤100)
接下来输入n行,每行有一个长度为m的字符串。
其中字符’.’表示可以通行
字符’*’表示无法通行
字符’O’表示出口
字符’X’表示班长的起始位置
输出
若能逃离 输出 "happy end"
否则输出 "bad end"
样例输入
2
5 5 13
.....
.***.
.*X*O
.*.*.
...*.
5 5 14
.....
.***.
.*X*O
.*.*.
...*.
样例输出
bad end
happy end
题目来源
kojimai
题目分析:应该找不到比这个更裸的BFS了。。。
#include <cstdio> #include <cstring> #include <queue> using namespace std; int const MAX = 25; char map[MAX][MAX]; int vis[MAX][MAX]; int dirx[4] = {1,-1,0,0}; int diry[4] = {0,0,-1,1}; int n, m, t; int sx, sy, ex, ey; struct Point { int x, y; int step; }; int BFS() { memset(vis,0,sizeof(vis)); queue<Point> q; Point node, t; node.x = sx; node.y = sy; node.step = 0; vis[sx][sy] = 1; q.push(node); while(!q.empty()) { node = q.front(); q.pop(); for(int i = 0; i < 4; i++) { t = node; t.x += dirx[i]; t.y += diry[i]; t.step++; if(t.x == ex && t.y == ey) return t.step; if(t.x < 0 || t.x >= n || t.y < 0 || t.y >= m || map[t.x][t.y] == '*' || vis[t.x][t.y]) continue; else { vis[t.x][t.y] = 1; q.push(t); } } } return 10000; } int main() { int T; scanf("%d", &T); while(T--) { scanf("%d %d %d",&n, &m, &t); for(int i = 0; i < n; i++) { scanf("%s", map[i]); for(int j = 0; j < m; j++) { if(map[i][j] == 'X') { sx = i; sy = j; } if(map[i][j] == 'O') { ex = i; ey = j; } } } int ans = BFS(); if(ans <= t) printf("happy end\n"); else printf("bad end\n"); } }
Dreaming
时间限制(普通/Java) : 1000 MS/ 3000 MS 运行内存限制 : 65536 KByte
总提交 : 88 测试通过 : 8
题目描述
我们定义一个数good当且仅当它只由a和b构成,且数位和sum各数位也仅由a和b构成。举个栗子:若a=1,b=2,那么13不是good,11是(都由a=1构成,数位和sum=2由b=2构成)。那么窝们定义一个数的长度为n,那么有多少个数是good呢?所求答案对10^9+7取模。
输入
多组样例。
每行包含三个数a,b,n(1<=a,b<=9,1<=n<=10^6)
输出
每组数据输出一个整数。
样例输入
1 3 3
样例输出
1
题目分析:首先我们求各种可能的和,然后分解判断是不是满足条件,接着求组合数就行了比如长度为10,3个a+7个b满足,则这种情况就有C(10,3)个,这题时间卡的太紧了,组合数要用阶乘+模逆元算,阶乘得预处理,此代码目前是这题得最快速度
#include <cstdio> #define ll long long int const MAX = 1e6 + 2; int const MOD = 1e9 + 7; ll fac[MAX]; int n, a, b; void pre() { fac[0] = fac[1] = 1; for(int i = 2; i <= MAX; i++) fac[i] = (fac[i - 1] * i) % MOD; } bool judge(int x) { while(x) { if(x % 10 != a && x % 10 != b) return false; x /= 10; } return true; } ll inv(ll x) { ll res = 1, y = MOD - 2; while(y) { if(y & 1) res = (res * x) % MOD; x = (x * x) % MOD; y >>= 1; } return res; } ll C(int n, int m) { return fac[n] * inv(fac[m]) % MOD * inv(fac[n - m]) % MOD; } int main() { pre(); while(scanf("%d %d %d", &a, &b, &n) != EOF) { int ans = 0; for(int i = 0; i <= n; i++) { int sum = a * i + b * (n - i); if((sum % 10 != a) && (sum % 10 != b)) continue; else if(judge(sum / 10)) ans = (ans % MOD + C(n, i) % MOD) % MOD; } printf("%d\n", ans); } }
自动售货机
时间限制(普通/Java) : 1000 MS/ 3000 MS 运行内存限制 : 65536 KByte
总提交 : 56 测试通过 : 12
题目描述
教学楼有一台奇怪的自动售货机,它只售卖一种饮料,单价5元,并且只收5元、10元面值的货币,但是同学们都很喜欢喝。这个售货机里没有多余的找零,也就是说如果一个持有10元的同学第一个购买,则他不能获得5元找零,但是如果在他之前有一个持有5元的同学买了这种饮料,则他可以获得5元找零。
假设售货机的货源无限,每人只买一罐,现在有N个持有5元的同学和M个持有10元的同学想要购买,问一共有多少种排队方法可以让每个持有10元的同学都获得找零。(这里的排队方法以某一位置上人持的钱数来分,即只要同一位置上的同学所持钱的数目相同,就算同一种排队方法)
输入
多组测试数据
每组包含两个整数N,M(1<=M<=N<=1000),分别表示持有5元和10元的同学个数。
输出
输出一个整数,表示排队方法总数。由于结果可能很大,所以结果需要模1000000007。
样例输入
1 1
2 1
3 1
样例输出
1
2
3
题目来源
hjp
题目分析:这题其实很简单,开始想的太复杂了,开始当作卡特兰数 (Catalan数)做其实就是(C(n+m, m)%mod - C(n+m, m-1)%mod)%mod,数组递推组合数T了 ,用java写大数结果noj上mle,连乘组合数取余写跪了,下面说这题应该怎么做。
其实就是一个dp,dp[i][j]表示有i个人有5元,j个人有10元的排队方案数,我们可以发现:
dp[i][0] = 1,因为大家都只有5元,怎么排都是一种方案
i < j时dp[i][j] = 0,因为有5元的人比有10元的少,必然会出现找不开的情况,那么此时方案数就是0
不是以上两种情况时:dp[i][j]的方案数由dp[i - 1][j] + dp[i][j - 1]递推得到,考虑第m+n个人的状态
1.第m+n个人100,m+n-1里有m个50,n-1个100则dp[m][n-1]
2.第m+n个人50,m+n-1里有m-1个50,n个100则dp[m-1][n]
#include <cstdio> #include <cstring> int dp[1005][1005]; int const MOD = 1e9 + 7; int main() { memset(dp, 0, sizeof(dp)); for(int i = 0; i <= 1000; i++) dp[i][0] = 1; for(int i = 1; i <= 1000; i++) for(int j = 1; j <= i; j++) dp[i][j] = ((dp[i][j - 1] % MOD) + (dp[i - 1][j] % MOD)) % MOD; int n, m; while(scanf("%d %d", &m, &n) != EOF) printf("%d\n", dp[m][n] % MOD); }
Prime
时间限制(普通/Java):1000MS/3000MS 运行内存限制:65536KByte
总提交:267 测试通过:11
比赛描述
给定n个数,求两两互斥的对数。互斥是指两个数的最大公约数是1
输入
第一行为样例数T(T<=5)
对每个样例,第一行为一个整数n(2=<n<=10^5),代表数的个数。
接下来一行包含n个数,a1,a2,…,an(1<=ai<=10^5)
输出
对于每个样例,在一行输出答案。
样例输入
1
2
2 3
样例输出
1
#include <cstdio> #include <cstring> #include <algorithm> #define ll long long using namespace std; int const MAX = 1e5 + 5; int p[MAX], cnt[MAX], num[MAX], mob[MAX]; bool prime[MAX]; int pnum, ma, n; void Mobius() //求解莫比乌斯函数 { pnum = 0; mob[1] = 1; memset(prime, true, sizeof(prime)); for(int i = 2; i < MAX; i++) { if(prime[i]) { p[pnum ++] = i; mob[i] = -1; } for(int j = 0; j < pnum && i * p[j] < MAX; j++) { prime[i * p[j]] = false; if(i % p[j] == 0) { mob[i * p[j]] = 0; break; } mob[i * p[j]] = -mob[i]; } } } ll cal() { ll ans = (ll) n * (n - 1) / 2; for(int i = 2; i <= ma ; i++) { num[i] = 0; for(int j = i; j <= ma; j += i) num[i] += cnt[j]; //得到gcd为i的集合的元素个数 } for(int i = 2; i <= ma; i++) ans += (ll) mob[i] * num[i] * (num[i] - 1) / 2; return ans; } int main() { Mobius(); int T; scanf("%d", &T); while(T--) { memset(cnt, 0, sizeof(cnt)); ma = 0; scanf("%d", &n); for(int i = 0; i < n; i ++) { int tmp; scanf("%d", &tmp); cnt[tmp] ++; ma = max(ma, tmp); } printf("%I64d\n", cal()); } }
KSS的金牌梦1
时间限制(普通/Java) : 3000 MS/ 9000 MS 运行内存限制 : 65536 KByte
总提交 : 56 测试通过 : 7
题目描述
KSS是nupt集训队里公认的最具有金牌实力的选手,熟练掌握多种金牌算法,但是由于队友水平太菜和自身情绪不稳定,一直没能拿到金牌。KSS为了圆梦,想为自己制定一个训练计划,那么问题来了:
ACM中有许多算法之间是有单方面依赖关系的,比如:想学会A,就必须先学B,由于KSS很聪明,所以它可以学完A再学B;当然也存在两种或多种算法相互交融的情况,比如:想学会A,就必须先学B,想学会B,就必须先学A,这种情况KSS就不知从何下手了。
现在给出KSS打算学习的一些算法之间的依赖关系,KSS将尽自己最大的努力去学习这些算法。再给出比赛会出现的算法,如果KSS能学会超过70%的比赛算法,他就能圆梦,否则,他只能含恨退役。
输入
多组测试用例。
第一行一个整数N(0<=N<=250000)表示有N对算法间存在依赖关系,保证涉及的算法总数不超过500
接下来N行每行有两个字符串(以空格分割),表示前一个算法依赖后一个算法,第N+1行有一个整数M(0<M<=1000)表示比赛会出现M个算法,接下来M行每行有一个字符串表示比赛出现的算法。(字符串保证不含空格)
输出
如果KSS可以圆梦,输出“Excelsior!”,否则,输出“KSS have a dream!”。(不用输出引号)
样例输入
4
Aho-Corasickautomaton KMP
Aho-Corasickautomaton trietree
Inclusion-ExclusionPrinciple Mobiusinversion
Mobiusinversion Inclusion-ExclusionPrinciple
5
KMP
trietree
Aho-Corasickautomaton
Splay
Suffixarray
样例输出
KSS have a dream!
提示
对于样例,KSS可以学会KMP、trietree、Aho-Corasickautomaton,但是并不能学会Inclusion-ExclusionPrinciple、Mobiusinversion,所以只能掌握60%的比赛算法
题目来源
hjp
题目分析:最伤心的一题。。。其实并不难可是全场就2人过还是在最后时候,所以并没有开它而是选择一直被数论坑着,赛后一下就补出来了。
这题就是裸的拓扑排序,出题人比较良心,没有卡map和cin的时间,不然字符串hash写就麻烦了,所以直接map存一下,建个图,拓扑排个序最后判断一下就行了,吐槽一下,我还是相信kss可以拿到金牌的
简单说下拓扑排序,就是用栈维护一个入读为0的点集,每次删点(出栈)然后修改图上各剩余点的入度,再将入度为0的点入栈,一直到栈为空,即不存在入度为0的点为止
#include <cstdio> #include <cstring> #include <stack> #include <map> #include <string> #include <iostream> using namespace std; map <string, int> mp; map <string, int> :: iterator it; int const MAX = 505; int m, n, cnt; int g[MAX][MAX], ind[MAX], tmp[MAX]; int re[MAX]; string s1, s2; int TopoSort() { bool flag = false; int len = 0; memcpy(tmp, ind, sizeof(ind)); stack <int> s; for(int i = 0; i < cnt; i++) if(!tmp[i]) s.push(i); while(!s.empty()) { int pos = s.top(); s.pop(); re[pos] ++; len ++; for(int i = 0; i < cnt; i++) if(g[pos][i] && --tmp[i] == 0) s.push(i); } return len; } int main() { while(scanf("%d", &m) != EOF) { mp.clear(); cnt = 0; memset(g, 0, sizeof(g)); memset(ind, 0, sizeof(ind)); memset(re, 0, sizeof(re)); while(m --) { cin >> s1 >> s2; it = mp.find(s1); if(it == mp.end()) mp[s1] = cnt++; it = mp.find(s2); if(it == mp.end()) mp[s2] = cnt++; g[mp[s2]][mp[s1]] = 1; ind[mp[s1]]++; } int ans = TopoSort(); bool flag = false; scanf("%d", &n); while(n --) { cin >> s1; it = mp.find(s1); if(it == mp.end()) //如果这个算法没出现过,kss肯定就跪键盘了 { flag = true; continue; } if(!re[mp[s1]]) //如果这个算法出现过,可是kss没学会。。可怜的kss { flag = true; continue; } } if(flag) printf("KSS have a dream!\n"); else printf("Excelsior!\n"); } }
Football
时间限制(普通/Java) : 1000 MS/ 3000 MS 运行内存限制 : 65536 KByte
总提交 : 254 测试通过 : 64
题目描述
现在你是一名足球经理,你的队伍将参加“南邮杯”的比赛。然而你拥有预知未来的能力,你可以预见你的队伍接下来进行的n场比赛每场的进球数和失球数。每胜一场队伍可得3分,平一场可得1分,输一场得0分。然而“南邮杯”是有黑幕的,你通过砸钱现在可以买到m个进球,问现在如何安排这m个进球,可以使得队伍获得最大的积分,求出这个最大的积分。
输入
多样例输入。
第一行给出n(1<=n<=10)和m(0<=m<=20)分别代表你队伍进行的比赛数以及队伍可买的进球数。
接下来n行,每行分别有两个数x和y分别表示该场比赛在没有买进球的情况下你队伍的进球数和失球数。
输出
对于每个样例答案输出一行输出一个整数,表示通过买球的方式你的队伍可获得的最大积分。
样例输入
2 1
1 1
1 1
3 2
1 3
3 1
2 2
4 10
1 1
2 2
1 3
0 4
样例输出
4
6
12
题目分析:签到题,按差值(x - y)从大到小排序贪心,差值大于0的不用处理,小于等于0的模拟一下
#include <cstdio> #include <cstring> #include <algorithm> using namespace std; int n, m; struct Data { int x, y; int val; }d[100]; bool cmp(Data a, Data b) { return a.val > b.val; } int main() { while(scanf("%d %d", &n, &m) != EOF) { for(int i = 0; i < n; i++) { scanf("%d %d", &d[i].x, &d[i].y); d[i].val = d[i].x - d[i].y; } sort(d, d + n, cmp); for(int i = 0; i < n; i++) { if(d[i].val > 0) continue; else { while(d[i].val <= 0 && m > 0) { m --; d[i].val ++; } } if(m == 0) break; } int ans = 0; for(int i = 0; i < n; i++) { if(d[i].val > 0) ans += 3; if(d[i].val == 0) ans += 1; } printf("%d\n", ans); } }
法师
时间限制(普通/Java) : 1000 MS/ 3000 MS 运行内存限制 : 65536 KByte
总提交 : 172 测试通过 : 28
题目描述
说到法师,也许大家第一反应便是脆弱的身躯与强大的爆发能力。诚然如此,在《炉石传说》中,法师拥有着最高伤害的单体法术——炎爆术,同时还有同样高伤害的火球术。但法师并不仅限于此,如果说这两张火系法术代表着的是法师的爆发。那么冰系法术就代表了法师的控制,冰霜新星、冰锥术以及暴风雪和寒冰箭都能够使对手冻结。
每张卡牌能造成一定的伤害,同时也要花费一定的法力水晶。当法力水晶不够的时候,你便不能打出相应的卡牌。
为了简单起见,我们只考虑以下几张卡牌。
寒冰箭 :消耗2点法力水晶,对一个角色造成3点伤害,并使其冻结。
冰枪术:消耗1点法力水晶,使一个角色冻结,如果它已经被冻结,则改为对其造成4点伤害。
火球术:消耗4点法力水晶,造成6点伤害。
炎爆术:消耗10点法力水晶,造成10点伤害。
现在,告诉你现在拥有的法力水晶,以及手上拥有的这四种卡牌的数目(可能为0),问你能对敌方英雄造成多少点伤害。
输入
第一行为一个正整数T,表示有T组数据。
每组数据第一行有1个整数: n表示当前拥有的法力水晶个数0<=n<=10。
第二行为四个整数a,b,c,d分别表示拥有寒冰箭、冰枪术、火球术、炎爆术的数目。0<=a,b,c,d<=10.
输出
一个整数表示最大可能造成的伤害值。
样例输入
2
9
0 0 3 0
5
2 2 1 1
样例输出
12
11
作者:伟大的css
题目分析:css出题太良心了,看看数据范围,直接暴力搞一下,不过不知道有没有贪心或者dp解法
#include <cstdio> #include <algorithm> using namespace std; int main() { int T; scanf("%d", &T); while(T--) { int a, b, c, d, n; scanf("%d", &n); scanf("%d %d %d %d", &a, &b, &c, &d); int ans = 0; for(int i = 0; i <= a; i++) { for(int j = 0; j <= b; j++) { for(int k = 0; k <= c; k++) { for(int l = 0; l <= d; l++) { if(2 * i + 1 * j + 4 * k + 10 * l <= n) { if(i > 0) //用寒冰箭冰冻 ans = max(ans, 3 * i + 4 * j + 6 * k + 10 * l); else { if(j >= 1) //用冰枪术冰冻 ans = max(ans, 4 * (j - 1) + 6 * k + 10 * l); else ans = max(ans, 6 * k + 10 * l); } } } } } } printf("%d\n", ans); } }
送花
时间限制(普通/Java) : 1000 MS/ 3000 MS 运行内存限制 : 65536 KByte
总提交 : 115 测试通过 : 40
题目描述
萌妹纸一般都比较喜欢漂亮的鲜花。每逢各种节日,她们都想收到鲜花作为礼物。如果你是有妹纸滴人,经常不送妹纸花的话,结果可想而知了。
当然咯,妹纸都是通情达理的,不会因为某几次你木有送花,就发你好人卡了。王童鞋作为一个比较节俭(抠门)的人便知道这一道理,因此他想在妹纸不给他发好人卡的前提下,送尽量少的花。
为了简单起见,我们定义一个妹纸的幸福指数H(初始为0 )。如果某天幸福指数H小于0,那就。。。
如果某天妹纸收到了花,幸福指数H会增加ai,如果没收到,会下降bi。不同的日子送花对幸福指数的增加可能会有所不同,比如在2月14号送花就会比2月15号效果好~
即告诉你总天数n(1<=n<=365),每天收到花幸福指数的增加值ai(1<=ai<=10),没收到花幸福指数的降低值bi,求为了让妹纸的幸福指数H一直>=0,王童鞋至少要送妹纸多少朵花。
输入
第一行为一个正整数T,表示有T组数据。
每组数据第一行有1个整数: n表示总天数1<=n<=365。
第二行为n个整数ai表示第i天收到花幸福指数的增加值,1<=ai<=10。第三行为n个整数bi表示第i天没收到花幸福指数的下降值,1<=bi<=10。
输出
一个整数表示最少需要送多少朵花。
样例输入
2
1
3
4
5
5 2 10 1 1
1 1 1 5 5
样例输出
1
2
作者:伟大的kss
题目分析:据说这题数据n最大是10,贪心可搞,不过还是dp搞的。
dp[i][j]表示前i天妹子幸福值为j的送花数
#include <cstdio> #include <cstring> #include <algorithm> using namespace std; int const MAX = 400; int const INF = 0x3fffffff; int dp[MAX][4000]; int a[MAX], b[MAX]; int main() { int T, n; scanf("%d",&T); while(T--) { int ans = INF; int suma = 0; scanf("%d",&n); memset(dp, -1, sizeof(dp)); dp[0][0] = 0; for(int i = 1; i <= n; i++) { scanf("%d", &a[i]); suma += a[i]; } for(int i = 1; i <= n; i++) scanf("%d",&b[i]); for(int i = 1; i <= n; i++) { for(int j = 0; j <= suma - a[i]; j++) { if(dp[i - 1][j] == -1) //前一天的状态不存在 continue; if(dp[i][j + a[i]] == -1) //当天状态不存在则由前一天推出来 dp[i][j + a[i]] = dp[i - 1][j] + 1; //当天状态存在则取最小,即判断前一天幸福值为j且当天送花得到的当天状态值 //是不是比原来的小,是就更新 else dp[i][j + a[i]] = min(dp[i][j + a[i]], dp[i - 1][j] + 1); } //下面是不送花的情况,和上面类似 for(int j = b[i]; j <= suma; j++) { if(dp[i - 1][j] == -1) continue; if(dp[i][j - b[i]] == -1) dp[i][j - b[i]] = dp[i - 1][j]; else dp[i][j - b[i]] = min(dp[i][j - b[i]], dp[i - 1][j]); } } //取前n天妹子幸福值大于等于0时送花的最小值 for(int j = 0; j <= suma; j++) { if(dp[n][j] == -1) continue; ans = min(ans, dp[n][j]); } printf("%d\n", ans); } }