http://acm.hdu.edu.cn/diy/contest_show.php?cid=36390
能猜对多少呢?
Time Limit : 3000/1000ms (Java/Other)
Memory Limit : 65535/32768K (Java/Other)
Problem Description
由于疫情的原因,大家最近都在家学习,但是这样有个问题,作业只能在网上提交。
而这样的问题导致大家都不想拿草稿纸计算,也不想动脑子,就想着随机猜答案!
老师布置了 n 道单项选择题,每道题目分别有 a[i] 个选项,而对于每道题,你都会随机猜一个答案,等所有选项都填好以后就急迫地点击提交。
但是系统竟然在这个时候出BUG了!每个题的填写的答案都跑到下一个题那里去了(最后一个题到了第一个题那里)。那么请问这时你做对的题目数期望是多少呢?
Input
输入包含 T 组数据,即第一行输入一个正整数 T (T ≤ 100)。
每组数据包含两行:
第一行一个正整数 n (n ≤ 10000);
第二行 n 个正整数,分别表示 a[i] (a[i] ≤ 1e4)。
Output
输出包含 T 行,每行一个保留两位小数的数字,表示每组数据的答案。
Sample Input
1
3
3 3 3
Sample Output
1.00
solution
#include<iostream> #include<algorithm> #include<cstdio> using namespace std; int main() { int T; scanf("%d",&T); while(T--){ int n; scanf("%d",&n); int a[n+1]; for(int i=0;i<n;++i) scanf("%d",&a[i]); double ans=0; for(int i=1;i<n;++i) ans+=1.0/max(a[i],a[i-1]); ans+=1.0/max(a[n-1],a[0]); printf("%.2f\n",ans); } return 0; }
分两种情况讨论:
第一种情况是 第一题有5个选项 第二题3个选项
第二种情况是 第一题有3个选项 第二题5个选项
前者做对第二题概率是1/5
后者也是
来做做回文串吧
Problem Description
这题就直入主题吧。
给定一个长度为 n 的字符串,你需要选择它的一个前缀,在后面接上加上它的一个后缀,可以得到一个“前后缀串”(选择的前缀后都可以为空串,但总长度不超过原串)。如果这个串回文串那就更好了,所以问题就是,最长的回文前后缀串长度是多少呢?
Input
输入包含 T (T ≤ 30) 组数据。
接下来有 T 行,每行一个字符串,字符串长度不超过 1000。
Output
输出包含 T 行,每行一个正整数表示最长的回文前后缀串的长度。
Sample Input
1
abcefedcba
Sample Output
9
(Hint: 最长的为 abcefecba,前缀取abcefe,后缀取cba)
solution
#include <algorithm> #include <cstdio> #include <iostream> #include <stack> #include <string> using namespace std; string s; int pos; inline int findleft(){ int L=pos,R=s.length()-pos-1; char ch=s[L]; for(;L<R;R--){ if(ch==s[R]){ int l=L+1,r=R-1; while(l<r&&s[l]==s[r])l++,r--; if(l>=r) return R-L+1; } } return 1; } inline int findright(){ int L=pos,R=s.length()-pos-1; char ch=s[R]; for(;L<R;++L){ if(ch==s[L]){ int l=L+1,r=R-1; while(l<r&&s[l]==s[r])l++,r--; if(l>=r) return R-L+1; } } return 1; } int solve() { int L=0,R=s.length()-1; for(; s[L]==s[R]&&L<R; L++,R--); pos=L; int ans=L*2; //printf("pos=%d\n",pos); --L,++R; if(R-L>1)ans+=max(findleft(),findright()); return ans; } int main() { int T,n; scanf("%d",&T); while(T--) { cin>>s; printf("%d\n",solve()); } return 0; }
两端匹配回文串,再搜索左中段回文串和右中段回文串,比出max相加即得结果。
最小生成树
Problem Description
由于种种奇怪的原因,这道题目被换成了考察最小生成树了。
有 n 个节点,然后给定 n * n 的矩阵,其中 a[i][j] 这个元素表示节点 i 到节点 j 之间边的边权。然后求最小生成树。本题请不要在网上查阅资料,自行完成。
Input
输入还是包含 T (T ≤ 4) 组数据。
每组数据先给定一个正整数 n (n ≤ 500);
然后再给出一个 n * n 的矩阵,矩阵中的元素大小不超过 1e4。
(矩阵元素满足 a[i][i] = 0, a[i][j]=a[j][i])
Output
输出也要包含 T 行,每行一个正整数,表示每组数据的答案啦。
Sample Input
1
3
0 1 1
1 0 1
1 1 0
Sample Output
2
solution
//kruskal #include <algorithm> #include <cstdio> #include <iostream> using namespace std; const int maxn = 500*500 + 7; int bin[maxn]; int n,m; struct edge { int u, v, w; } edges[maxn]; inline void unit() { for (int i = 0; i <= m; i++) bin[i] = i; } inline int Find(int x) { int px = x; while (px != bin[px]) px = bin[px]; return px; } inline void merge(int x, int y) { int fx = Find(x); int fy = Find(y); if (fx != fy) bin[fx] = fy; } inline bool cmp(edge a, edge b) { //定义排序规则 return a.w < b.w; } inline void Kruskal() { long long int sumweight = 0; //生成树的权值 int num = 0; //已选用的边的数目 int u, v; //选用边的两个顶点 unit(); //初始化 parent[]数组 for (int i = 0; i < m; i++) { u = edges[i].u; v = edges[i].v; if (Find(u) != Find(v)) { //判断其是否在同一个连通分量 //printf("%d %d %d\n", u, v, edges[i].w); sumweight += edges[i].w; num++; merge(u, v); } if (num >= n - 1) break; } printf("%lld\n", sumweight); } int main() { int T; scanf("%d",&T); while(T--){ scanf("%d",&n);//读入顶点个数 n int x; m=0; for(int i=0; i<n; ++i) { for(int j=0; j<n; ++j) { scanf("%d",&x); if(x) { edges[m].u = i+1; edges[m].v = j+1; edges[m++].w = x; } }} sort(edges, edges + m, cmp);//排序 Kruskal(); } return 0; }
//prim #include "bits/stdc++.h" using namespace std; const int maxn = 5e2+7; int n; int dis[maxn], vis[maxn], e[maxn][maxn]; int Prim() { int ans=0; for(int i=0; i<=n; ++i) dis[i]=2e9, vis[i]=0; //初始化 dis[1]=0; //prim算法任选起点,于是可以选择1为起点 for(int i=1; i<=n; ++i) { int u=0; //注意dis[0]已经初始化为无穷大了,不用管了 for(int j=1; j<=n; ++j) if(!vis[j]) { if(dis[j]<dis[u]) u=j; } vis[u]=1; ans+=dis[u]; //更新答案啦 for(int j=1; j<=n; ++j) if(!vis[j]) { //拿u点来更新新拓展的边 if(dis[j]>e[u][j]) dis[j]=e[u][j]; } } return ans; } void solve() { scanf("%d", &n); for(int i=1; i<=n; ++i) for(int j=1; j<=n; ++j) scanf("%d", &e[i][j]); printf("%d\n", Prim()); } int main() { int T; cin>>T; while(T--) solve(); }