A. Vowel Count(模拟)
思路:
按照题意统计元音字母个数模拟即可
#include<iostream> #include<algorithm> using namespace std; int main() { int t; cin>>t; while(t--){ string s; cin>>s; int num=0; int len=s.size(); for(int i=0;i<len;i++) if(s[i]=='a'||s[i]=='e'||s[i]=='i'||s[i]=='o'||s[i]=='u') num++; cout<<s<<endl; if(num>len-num) cout<<1<<endl; else cout<<0<<endl; } return 0; }
B. Soccer Standings(暴力枚举)
思路:
暴力枚举赢的次数跟输的次数,再判断得分是否合法
#include<iostream> #include<algorithm> using namespace std; int main() { int t,n,m; cin>>t; for(int i=1;i<=t;i++){ cin>>n>>m; cout<<"Team #"<<i<<endl; cout<<"Games: "<<n<<endl; cout<<"Points: "<<m<<endl; cout<<"Possible records:"<<endl; for(int i=m/3;i>=0;i--){ if(i+m-3*i<=n) cout<<i<<"-"<<m-3*i<<"-"<<n-(i+m-3*i)<<endl; else break; } cout<<endl; } return 0; }
C. Jumping Frog(贪心)
思路:
先判断不可行的情况,如果有连续长度大于$d$的$X$,则无法通过
之后进行贪心求最小值,假设我们的当前位置为$pos$,那么我们可以从$pos+d+1$这个点开始往回找第一个为$.$的位置,这一次跳跃操作就跳至那里
不断进行前面的操作,就可以求出最小值
#include<iostream> #include<algorithm> using namespace std; int t,n,d; string str; int main(){ cin>>t; for(int cas=1;cas<=t;cas++){ cin>>n>>d>>str; cout<<"Day #"<<cas<<endl; cout<<n<<" "<<d<<endl; cout<<str<<endl; int cnt=0; for(int i=0;i<str.size();i++){ if(str[i]=='X'){ int j; for(j=i;j<str.size();j++) if(str[j]!='X') break; if(j-i>d) { cnt=-1; break; } i=j; } } if(cnt!=-1) for(int i=0;i<str.size();){ if(i+d+1>=str.size()-1) { cnt++; break; } if(str[i+d+1]=='.') i=i+d+1,cnt++; else{ int j; for(j=i+d+1;j>=i;j--) if(str[j]=='.') break; i=j;cnt++; } } cout<<max(cnt,0)<<endl<<endl; } }
D. Fujiyama Thursday(贪心)
思路:
根据贪心的思想,吃饭越快的人肯定坐越快的车,所以我们将每个人吃饭的时间加上坐车的时间排序后去最大值就好了
#include<iostream> #include<algorithm> using namespace std; const int maxn=1e3+10; int a[maxn],b[maxn]; int main() { int t,c,n; cin>>t; for(int cas=1;cas<=t;cas++){ cin>>c; n=4*c; for(int i=1;i<=c;i++) cin>>a[i]; for(int i=1;i<=n;i++) cin>>b[i]; sort(a+1,a+1+c); sort(b+1,b+1+n); reverse(b+1,b+1+n); for(int i=1;i<=n;i++){ b[i]+=a[(i-1)/4+1]; } sort(b+1,b+1+n); cout<<"Trip #"<<cas<<": "<<b[n]<<endl; } return 0; }
E. Chain Email(Tarjan缩点)
思路:
根据观察,我们发现有两种人都能无限收到邮件
$①$在环内的人,$②$从环内出发所能到达的所有点
所以我们用$tarjan$进行缩点,然后再进行$dfs$,求出连接的点
#include<iostream> #include<algorithm> #include<map> #include<cstring> using namespace std; const int N=55,M=3000; map<int,string> mp; map<int,int> mpp; map<int,int> mp_id; int h[N],hs[N],e[M],ne[M],idx; int dfn[N],low[N],stk[N],in_stk[N],id[N],size_scc[N]; int scc_cnt,timestamp,top,n,x,flag; vector<int> v[N]; void add(int h[],int a,int b) { e[idx]=b,ne[idx]=h[a],h[a]=idx++; } void tarjan(int u) { dfn[u] = low[u] = ++ timestamp; stk[ ++ top] = u, in_stk[u] = true; for (int i = h[u]; ~i; i = ne[i]) { int j = e[i]; if (!dfn[j]) { tarjan(j); low[u] = min(low[u], low[j]); } else if (in_stk[j]) low[u] = min(low[u], dfn[j]); } if (dfn[u] == low[u]){ ++ scc_cnt; int y; do { y = stk[top -- ]; in_stk[y] = false; id[y] = scc_cnt; size_scc[scc_cnt]++; v[scc_cnt].push_back(y); } while (y != u); } } void init() { flag=0; memset(h,-1,sizeof h); memset(hs,-1,sizeof hs); top=timestamp=scc_cnt=idx=0; mp.clear(); mpp.clear(); mp_id.clear(); for(int i=0;i<=n;i++) stk[i]=in_stk[i]=id[i]=low[i]=dfn[i]=size_scc[i]=0,v[i].clear(); } void dfs_hs(int ver) { if(size_scc[ver]>1) mp_id[ver]=1,flag=1; for(int i=hs[ver];~i;i=ne[i]) { int j=e[i]; dfs_hs(j); } } void dfs_h(int u) { if(mpp[u]) return; mpp[u]++; for(int i=h[u];~i;i=ne[i]){ int j=e[i]; dfs_h(j); } } int main() { int t,cnt; cin>>t; for(int cas=1;cas<=t;cas++){ printf("Chain Email #%d: ",cas); cin>>n>>x; init(); for(int i=1;i<=n;i++){ string s; cin>>s; mp[i]=s; } for(int i=1;i<=n;i++){ cin >>cnt; while(cnt--){ int u; cin>>u; add(h,i,u); } } for(int i=1;i<=n;i++) if(!dfn[i]) tarjan(i); for(int i=1;i<=n;i++){ for(int j=h[i];~j;j=ne[j]){ int k=e[j]; int a=id[i],b=id[k]; if(a!=b) add(hs,a,b); } } dfs_hs(id[x]); if(flag==0){ printf("Safe chain email! "); continue; } for(int i=1;i<=scc_cnt;i++) if(mp_id[i]) for(int j=0;j<v[i].size();j++) dfs_h(v[i][j]); for(int i=1;i<=n;i++) if(mpp[i]) cout <<mp[i]<<" "; printf(" "); } return 0; }
I. Shopping Spree(DP)
思路:
$f[i][j]$表示:前i个数选择$j$个数的最大值。(特判$n=1$)
#include<bits/stdc++.h> using namespace std; const int N=550; int f[N][N],a[N]; int main() { int n; cin>>n; for(int i=1;i<=n;i++){ int m; cin>>m; for(int j=1;j<=m;j++) cin>>a[j]; f[1][1]=a[1]; for(int j=2;j<=m;j++){ for(int k=1;k<=j/2;k++){ f[j][k]=max(f[j-1][k],f[j-1][k-1]+a[j]); } } printf("Spree #%d: ",i); cout<<max(f[1][1],f[m][m/2])<<endl; } return 0; }
J. Factorial Products(对数函数,思维)
思路:
直接进行比较的话肯定会溢出,用大数的话会超时
由于仅仅比较大小,我们可以考虑对数函数,由于$log(x*y)=log(x)+log(y)$这样的性质,我们可以轻松解决乘法溢出问题
为了防止求阶乘超时,我们可以先预处理出$log(i) 1≤i≤2510$
最后由于$double$会损失精度,所以我们需要用$eps$来判断等于
#include<iostream> #include<algorithm> using namespace std; typedef long long ll; const double eps=1e-7; int t,A,B,C,T; int num[2510]; double res[2510]; void init() { for(int i=2;i<2510;i++) res[i]=res[i-1]+log(i); } int main() { init(); scanf("%d",&t); while(t--){ scanf("%d%d%d",&A,&B,&C); double a=0,b=0,c=0; for(int i=1;i<=A;i++){ int x; scanf("%d",&x); a+=res[x]; } for(int i=1;i<=B;i++){ int x; scanf("%d",&x); b+=res[x]; } for(int i=1;i<=C;i++){ int x; scanf("%d",&x); c+=res[x]; } printf("Case #%d: ",++T); if(fabs(a-b)<=eps){ if(c>a) puts("C"); else puts("TIE"); } else if(a>b){ if(fabs(a-c)<=eps) puts("TIE"); else if(a>c) puts("A"); else puts("C"); } else{ if(fabs(b-c)<=eps) puts("TIE"); else if(b>c) puts("B"); else puts("C"); } } return 0; }