省赛部分解题报告
发现省赛之后自己变懒了唉,现在就做了这几个先写一些吧:
热身赛:
http://acm.sdut.edu.cn/sdutoj/problem.php?action=showproblem&problemid=2404
求Super Prime,打个表就能过:
#include <iostream> #include <cstring> #include <cstdio> #define maxn 100017 using namespace std; int p[maxn],isp[maxn]; bool hash[maxn]; int len; void init() { int i,j; memset(p,0,sizeof(p)); for (i = 2; i*i < maxn; ++i) { if (!p[i]) { for (j = 2*i; j < maxn; j += i) { p[j] = 1; } } } len = 0; for (i = 2; i < maxn; ++i) { if (!p[i]) isp[len++] = i; } memset(hash,false,sizeof(hash)); for (i = 0; i < len; ++i) { int tmp = isp[i]; for (j = i + 1; j < len; ++j) { tmp += isp[j]; if (tmp >= 100000) break; if (!hash[tmp] && !p[tmp]) hash[tmp] = true; } } } int main() { init(); int t,n,cas = 1; scanf("%d",&t); while (t--) { scanf("%d",&n); if (hash[n]) printf("Case %d: yes\n",cas++); else printf("Case %d: no\n",cas++); } return 0; }
http://acm.sdut.edu.cn/sdutoj/problem.php?action=showproblem&problemid=2405
这题很坑爹啊,比赛时我写了个9!的TLE 赛后FXH的直接调用那个求组合数的函数都过了。我就又敲了一遍其实只要加个小剪枝就能过唉,然后是枚举六个数要考虑算出来的那三个数是否存在于给定的九个数中,还要检查是三个数是否被枚举过就好了。
9!
#include <iostream> #include <algorithm> #include <cstring> #include <cstdio> #define maxn 400000 using namespace std; int a[11],tmp[11]; int t[maxn][11]; int len,ans,sum; bool vt[11]; bool isok() { if (sum != tmp[0] + tmp[1] + tmp[2]) return false; if (sum != tmp[3] + tmp[4] + tmp[5]) return false; if (sum != tmp[6] + tmp[7] + tmp[8]) return false; if (sum != tmp[0] + tmp[3] + tmp[6]) return false; if (sum != tmp[1] + tmp[4] + tmp[7]) return false; if (sum != tmp[2] + tmp[5] + tmp[8]) return false; return true; } bool good() { int i,j; for (i = 0; i < len; ++i) { for (j = 0; j < 9; ++j) { if (t[i][j] != tmp[j]) break; } if (j == 9) return false; } for (i = 0; i < 9; ++i) t[len][i] = tmp[i]; len++; return true; } void dfs(int pos,int ct) { int i; tmp[ct] = a[pos]; if (ct == 8) { if (isok() && good()) { ans++; } return ; } for (i = 0; i < 9; ++i) { if (!vt[i]) { vt[i] = true; dfs(i,ct + 1); vt[i] = false; } } } int main() { int t,i,cas = 1; scanf("%d",&t); while (t--) { len = ans = sum = 0; for (i = 0; i < 9; ++i) { scanf("%d",&a[i]); sum += a[i]; } //就是这个剪枝,唉。。当时没考虑全啊。 if (sum%3 != 0) { printf("Case %d: 0\n",cas++); continue; } sum/=3; memset(vt,false,sizeof(vt)); for (i = 0; i < 9; ++i) { if (!vt[i]) { vt[i] = true; dfs(i,0); vt[i] = false; } } printf("Case %d: %d\n",cas++,ans); } return 0; }
6!
#include <iostream> #include <cstring> #include <cstdio> #define maxn 1000007 using namespace std; int tt[maxn][11]; int tmp[11],a[11]; int ans,len,sum; bool vt[11],hash[11]; //主要是当时没考虑到这个情况 bool yes(int pos,int L) { int j,i,pt = 0; memset(hash,false,sizeof(hash)); //把已经枚举出来的先都挖出去 for (j = 0; j < L; ++j) { for (i = 0; i < 9; ++i) { if (a[i] == tmp[j] && !hash[i]) { pt++; hash[i] = true; break; } } } if (pt == L) { //然后查看未枚举的三个数是不是计算出来的三个数 for (int i = 0; i < 9; ++i) { if (!hash[i] && a[i] == pos) { tmp[L] = pos; hash[i] = true; return true; } } return false; } else return false; } bool isok() { if (sum != tmp[0] + tmp[1] + tmp[2]) return false; if (sum != tmp[3] + tmp[4] + tmp[5]) return false; if (sum != tmp[6] + tmp[7] + tmp[8]) return false; if (sum != tmp[0] + tmp[3] + tmp[6]) return false; if (sum != tmp[1] + tmp[4] + tmp[7]) return false; if (sum != tmp[2] + tmp[5] + tmp[8]) return false; return true; } bool good() { int i,j; for (i = 0; i < len; ++i) { for (j = 0; j < 9; ++j) { if (tt[i][j] != tmp[j]) break; } if (j == 9) return false; } for (i = 0; i < 9; ++i) tt[len][i] = tmp[i]; len++; return true; } void dfs(int pos,int ct) { int i; tmp[ct] = a[pos]; if (ct == 5) { int x = sum - tmp[0] - tmp[3]; int y = sum - tmp[1] - tmp[4]; int z = sum - tmp[2] - tmp[5]; bool flag = false; if (yes(x,6) && yes(y,7) && yes(z,8)) { flag = true; } if (flag && isok() && good()) { ans++; } return ; } for (i = 0; i < 9; ++i) { if (!vt[i]) { vt[i] = true; dfs(i,ct + 1); vt[i] = false; } } } int main() { int t,i,cas = 1; scanf("%d",&t); while (t--) { sum = len = ans = 0; for (i = 0; i < 9; ++i) { scanf("%d",&a[i]); sum += a[i]; } if (sum%3 != 0) { printf("Case %d: 0\n",cas++); continue; } sum /= 3; memset(vt,false,sizeof(vt)); for (i = 0; i < 9; ++i) { if (!vt[i]) { vt[i] = true; dfs(i,0); vt[i] = false; } } printf("Case %d: %d\n",cas++,ans); } return 0; }
Pick apples
http://acm.sdut.edu.cn/sdutoj/problem.php?action=showproblem&problemid=2408
按比率贪心不是最优,所以不会过。只能考虑完全背包,可是完全背包给的数据有太大,不能纯完全背包。
思路:如果给定体积小于100000直接套安全背包做就行,如果体积大于1000000先放比率最优的直到v小于等于1000000时,然后再将剩余体积完全背包后加上大于1000000时得到的价值即可。注意数据范围LL,
#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> #define maxn 1000007 #define LL long long using namespace std; LL dp[maxn]; struct node { int s,val; }p[4]; int cmp(node x,node y) { return x.val*y.s > y.val*x.s; } int main() { int i,j,t; int cas = 1; scanf("%d",&t); LL v,sum; while (t--) { sum = 0; for (i = 0; i < 3; ++i) scanf("%d%d",&p[i].s,&p[i].val); sort(p,p + 3,cmp); scanf("%lld",&v); memset(dp,0,sizeof(dp)); if (v <= 1000000) { for (i = 0; i < 3; ++i) { for (j = p[i].s; j <= v; ++j) { if (dp[j] < dp[j - p[i].s] + p[i].val) dp[j] = dp[j - p[i].s] + p[i].val; } } } else { LL tv = v - 1000000; int num = tv/p[0].s + 1; sum = (LL)num*p[0].val; v -= (LL)num*p[0].s; for (i = 0; i < 3; ++i) { for (j = p[i].s; j <= v; ++j) { if (dp[j] < dp[j - p[i].s] + p[i].val) dp[j] = dp[j - p[i].s] + p[i].val; } } } LL M = 0; for (i = 1; i <= v; ++i) { if (M < dp[i]) M = dp[i]; } printf("Case %d: %lld\n",cas++,sum + M); } return 0; }
据说这道题号去年上海赛区的议题很相似,反正这种方法是听虎哥说的。orz虎哥。
首先按比率排序,如果不是最优的那种苹果所用的体积是最优苹果(每个)与该苹果(每个)的公倍数的话,那么这个体积应该用来装最优苹果。
假设按最优排序;
size1 size2 size3
val1 val2 val3
若2用的体积有V < size1*size2; 同时处以size2 的 n2 < size1;n2 表示第二优的苹果选多少个。最后的同理。所以
不是最优的苹果选择个数的范围是【0,size1)(其实这里求size1与size2 size3的最小公倍数才是最优,不过这里求两个积已经足够了) 枚举两个所有的取值即可;
#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> #define maxn 1000007 #define LL long long using namespace std; LL dp[maxn]; struct node { int s,val; }p[4]; int cmp(node x,node y) { return x.val*y.s > y.val*x.s; } int main() { int i,j,t; int cas = 1; scanf("%d",&t); LL v,sum; while (t--) { sum = 0; for (i = 0; i < 3; ++i) scanf("%d%d",&p[i].s,&p[i].val); sort(p,p + 3,cmp); scanf("%lld",&v); LL ans = 0; for (i = 0; i < p[0].s; ++i) { for (j = 0; j < p[0].s; ++j) { LL tmp = i*p[1].s + j*p[2].s; if (tmp > v) break; LL rest = v - tmp; sum = (rest/p[0].s)*p[0].val + i*p[1].val + j*p[2].val; if (sum > ans) ans = sum; } } printf("Case %d: %lld\n",cas++,ans); } return 0; }
The Best Seat in ACM Contest
http://acm.sdut.edu.cn/sdutoj/problem.php?action=showproblem&problemid=2409
模拟整个说明做就行。。注意一下边界就好了。
#include <iostream> #include <cstring> #include <cstdio> #define maxn 22 using namespace std; int map[maxn][maxn]; int as; int n,m; int dir[4][2] = {{1,0},{-1,0},{0,1},{0,-1}}; int main() { int t,i,j,k,cas = 1; scanf("%d",&t); while (t--) { scanf("%d%d",&n,&m); memset(map,0,sizeof(map)); for (i = 1; i <= n; ++i) { for (j = 1;j <= m; ++j) { scanf("%d",&map[i][j]); } } int sum = -99999999; int sx,sy; for (i = 1; i <= n; ++i) { for (j = 1; j <= m; ++j) { int tmp = 0; for (k = 0; k < 4; ++k) { int tx = i + dir[k][0]; int ty = j + dir[k][1]; if (tx < 0 || tx > n + 1 || ty < 0 || ty > m + 1) continue; if (map[i][j] > map[tx][ty]) { if (tx != 0 && tx != n + 1 && ty != 0 && ty != m + 1) tmp -= (map[i][j] - map[tx][ty]); else tmp -= 1; } else tmp += (map[tx][ty] - map[i][j]); } if (sum <= tmp) { sum = tmp; sx = i; sy = j; } } } printf("Case %d: %d %d %d\n",cas++,sum,sx,sy); } return 0; }
Pixel density
http://acm.sdut.edu.cn/sdutoj/problem.php?action=showproblem&problemid=2411
模拟题,不好写。我先用的strstr确定inches的位置然后往前往后查找,却出我们要的值就好了。。注意 3.5 inches 可以没有小数点的。。
还有注意空格可能任意多个,过滤掉空格。
#include <iostream> #include <cstdio> #include <cstring> #include <cmath> #define maxn 10007 using namespace std; double Pow(double a,int b) { double sum = 1.0; for (int i = 1; i <= b; ++i) sum *= a; return sum; } int main() { //freopen("data.in","r",stdin); //freopen("tmdata.out","w",stdout); int i,cas = 1; char s[maxn]; char tmp[8] = {"inches"}; int t; scanf("%d",&t); getchar(); while (t--) { gets(s); int len = strlen(s); char *pos = strstr(s,tmp); char *tpos = pos; tpos--; while (*(tpos) == ' ') --tpos; char tt[maxn] ={'0'}; int tl = 0; bool flag = false; int pot = 0; for (; *(tpos) != ' '; --tpos) { if (*(tpos) == '.') { flag = true; pot = tl; } tt[tl++] = *(tpos); } tt[tl] = '\0'; double a = 0,b = 0; if (!flag) { for (i = tl - 1; i >= 0; --i) a = a*10 + tt[i] - '0'; } else { for (i = 0; tt[i] != '.'; ++i) { a = a*0.1 + tt[i] - '0'; } a = a/10; for (i = tl - 1; i > pot; --i) { b = b*10 + tt[i] - '0'; } } double inch = b + a; while (*(tpos) == ' ') --tpos; tpos++; char name[maxn] = {'0'}; int nal = 0; for (i = 0; &s[i] != tpos; ++i) { name[nal++] = s[i]; } name[nal] = '\0'; for (; *(pos) != ' '; ++pos){} while (*(pos) == ' ') ++pos; double wp = 0; for (; *(pos) != '*'; ++pos) wp = wp*10 + *(pos) - '0'; pos++; double hp = 0; for (; *(pos) != ' '; ++pos) hp = hp*10 + *(pos) - '0'; while (*(pos) == ' ') pos++; pos--; char mark[maxn] = {'0'}; int ml = 0; for (i = len - 1; &s[i] != pos; --i) mark[ml++] = s[i]; int j = ml - 1; char markl[maxn] = {'0'}; for (i = 0; i < ml; ++i) markl[i] = mark[j --]; double dp = sqrt(wp*wp + hp*hp); if (inch != 0) dp = dp/inch; else dp = 0; //printf("%.5lf %.5lf %.5lf %.5lf %.5lf\n",a,b,inch,wp,hp); printf("Case %d: The ",cas++); for (i = 0; i < ml; ++i) { if (markl[i] >= 'A' && markl[i] <= 'Z') markl[i] += 32; printf("%c",markl[i]); } printf(" of %s's PPI is %.2lf.\n",name,dp); } return 0; }
Fruit Ninja II
http://acm.sdut.edu.cn/sdutoj/problem.php?action=showproblem&problemid=2416
高数里面求积分的题目,唉直接忘了的干活。。。
#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> #include <cmath> using namespace std; const double pi = acos(-1.0); int main() { double h,b,a,ans,sum; int t,cas = 1; scanf("%d",&t); while (t--) { scanf("%lf%lf%lf",&a,&b,&h); if (h > b) h = b; sum = 2.0*pi*a*b*b/3.0; ans = pi*a*b*(2*b/3.0 - h + (h*h*h)/(3.0*b*b)); sum = sum + sum - ans; printf("Case %d: %.3lf\n",cas++,sum); } return 0; }