前言:
还差B,J补完再写。
比赛感受:
还是很喜欢这套题的,可惜比赛时停电做了4题就溜了hhh
因为太菜了这篇只是写的简单题
第一次打rating赛,紫名快乐hhh
A: AOE还是单体? (贪心)
思路:
对于血量大于x的用AOE,反之用单体。
所以可以按照血量从小到大排序,用AOE击败n-x个人,剩x个人用单体击败。
这也就是兰子姐姐题解里的临界值hh
代码:
#include<bits/stdc++.h> typedef long long ll; using namespace std; const int maxn=1e6+7; ll a[maxn],n,x; int main(){ cin>>n>>x; ll sum=0; for(int i=1;i<=n;i++) cin>>a[i],sum+=a[i]; if(x>=n){ cout<<sum<<endl; return 0; } sort(a+1,a+1+n); ll res=a[n-x]*x; for(int i=n-x+1;i<=n;i++) res+=a[i]-a[n-x]; cout<<res<<endl; return 0; }
C.白魔法师 (并查集判连通块)
题意:
树上有黑白两种点,问把一个黑点变成白色后树上白色连通块的最大值。
思路:
因为n的范围比较友好,所以可以统计出白色连通块的大小,然后枚举修改哪一个黑节点,当前的答案就是他的相邻节点的所有白色连通块大小加上本身。
代码:
#include<bits/stdc++.h> using namespace std; const int maxn=1e6+7; int root[maxn];///并查集 存储父节点 int cnt[maxn];///存储每个连通块的大小 char s[maxn];///存储每个点的颜色 vector<int>e[maxn];///存边 int n; int Find(int x){ if(x!=root[x]) root[x]=Find(root[x]); return root[x]; } void Union(int x,int y){ x=Find(x),y=Find(y); if(x!=y){ root[x]=y; cnt[y]+=cnt[x]; } } int main() { cin>>n; cin>>s+1; for(int i=1;i<=n;i++) root[i]=i,cnt[i]=1; for(int i=1;i<n;i++){ int x,y; cin>>x>>y; e[x].push_back(y); e[y].push_back(x); if(s[x]=='W'&&s[y]=='W') Union(x,y); } int res=0; for(int i=1;i<=n;i++) if(s[i]=='W') res=max(res,cnt[Find(i)]); else{ int tmp=1; for(auto tt:e[i]) if(s[tt]=='W') tmp+=cnt[Find(tt)]; res=max(res,tmp); } cout<<res<<endl; return 0; }
D.抽卡 (逆元)
思路:
1-抽不中卡的概率p。p为(a[i]-b[i])/a[i]的乘积。然后就可以用逆元求解了。
#include<bits/stdc++.h> typedef long long ll; using namespace std; const int maxn=1e6+7; const ll mod=1e9+7; ll a[maxn],b[maxn]; ll ksm(ll a,ll b){ ll p=mod; ll res=1; while(b){ //&运算当相应位上的数都是1时,该位取1,否则该为0。 if(b&1) res=1ll*res*a%p;//转换为ll型 a=1ll*a*a%p; b>>=1;//十进制下每除10整数位就退一位 } return res; } int main(){ ll n;cin>>n; for(int i=1;i<=n;i++) cin>>a[i]; for(int i=1;i<=n;i++) cin>>b[i]; ll res=1; for(int i=1;i<=n;i++){ res=res*(a[i]-b[i])%mod*ksm(a[i],mod-2)%mod; } res=(1-res+mod)%mod; cout<<res<<endl; return 0; }
E.点击消除(栈)
思路:
用栈模拟一下消除的过程即可,如果栈为空或栈顶元素与当前元素不相等,当前元素就可以被放入栈中;否则,当前元素和栈顶元素消除,弹出栈顶元素。
代码:
#include<bits/stdc++.h> using namespace std; int main(){ string s;cin>>s; string res=""; stack<char>st; for(int i=0;i<s.size();i++){ if(st.empty()||st.top()!=s[i]) st.push(s[i]); else if(st.top()==s[i]) st.pop(); } bool flag=0; if(st.empty()) flag=1; while(!st.empty()){ res=res+st.top(); st.pop(); } if(flag) puts("0"); else{ for(int i=res.size()-1;i>=0;i--) cout<<res[i]; } return 0; }
E.疯狂的自我检索者(签到题)
思路:
要想平均分最小肯定是总和最小,这时候隐藏的分数都为1;
想要平均分最大肯定是总和最大,这时候隐藏的分数都为0;
代码:
#include<bits/stdc++.h> using namespace std; const int maxn=1e6+7; int a[maxn],n,m; int main(){ cin>>n>>m; int sum=0; for(int i=1;i<=n-m;i++) cin>>a[i],sum+=a[i]; double maxx=1.0*(sum+5*m)/n,minn=1.0*(sum+m)/n; printf("%.5f %.5f\n",minn,maxx); return 0; }
G.解方程(二分)
思路:
盲猜具有单调性(手动滑稽)。
其实是一个单调递增的函数。
二分答案即可,但是需要把eps设的小一点。
代码:
#include<bits/stdc++.h> typedef long long ll; using namespace std; const double eps=1e-7; ll a,b,c; bool check(double mid) { if((pow(mid,a)+log(mid)*b)>=c) return 1; return 0; } int main() { cin>>a>>b>>c; double l=0,r=1e9; while(r>=l){ double mid=1.0*(l+r)/2; if(check(mid)) r=mid-eps; else l=mid+eps; } printf("%.14f\n",r); return 0; }
H. 神奇的字母(二) (map+EOF)
思路:
用map记录一下出现的次数即可。考点是如何输入,真的是小白必须要知道的知识点啊。
代码:
#include<bits/stdc++.h> using namespace std; int main(){ map<char,int>mp; string s; while(getline(cin,s)){ for(int i=0;i<s.size();i++) if(s[i]!=' ') mp[s[i]]++; } int maxx=0; char pos; for(auto it=mp.begin();it!=mp.end();it++) if(maxx<it->second) maxx=it->second,pos=it->first; cout<<pos<<endl; return 0; }
I. 十字爆破 (开数组的小技巧)
思路:
用x[i]表示第i行的得分之和,y[i]表示第i列的得分之和。
那么每个格子(i,j)的得分就是x[i]+y[j]-a[i] [j]
但是数据范围是n*m=1e5,直接开二维数组又会爆内存。
可以用下面两种解决方法:一是用vector,二是开成a[n+10] [m+10]类型的。
代码:
#include<bits/stdc++.h> using namespace std; typedef long long ll; typedef pair<int,int>PII; #define I_int ll #define inf 0x3f3f3f3f inline ll read() { ll x=0,f=1;char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();} return x*f; } char F[200]; inline void out(I_int x) { if (x == 0) return (void) (putchar('0')); I_int tmp = x > 0 ? x : -x; if (x < 0) putchar('-'); int cnt = 0; while (tmp > 0) { F[cnt++] = tmp % 10 + '0'; tmp /= 10; } while (cnt > 0) putchar(F[--cnt]); //cout<<" "; } const int maxn=1e6+7; ll x[maxn],y[maxn]; void AC(){ int n,m; n=read();m=read(); ll a[n+5][m+5]; for(int i=1;i<=n;i++) for(int j=1;j<=m;j++){ ll t=read(); a[i][j]=t; x[i]+=t;y[j]+=t; } for(int i=1;i<=n;i++) for(int j=1;j<=m;j++){ out(x[i]+y[j]-a[i][j]); if(j==m) puts(""); else cout<<" "; } } int main(){ AC(); return 0; }