Educational Codeforces Round 155 (Rated for Div. 2)
\(A. Rigged!\)
直接取第一个人能举起的最大重量看他是否是冠军即可。
void solve(){
int n=read();
int fx=read(),ft=read();
int ans=fx;
for(int i=1;i<n;i++){
int x=read(),t=read();
if(x>=fx&&t>=ft)ans=-1;
}
cout<<ans<<'\n';
//puts(ans>0?"YES":"NO");
//puts(ans>0?"Yes":"No");
}
\(B. Chips on the Board\)
那么要么是每行都有一个,要么是每列都有一个(每列每行都有包括在里面)。
那么显然的取铺满的方向和,和另一方向的最小值,看看哪个方向更小即可。
void solve(){
int n=read();
vector<int>a(n),b(n);
int minna=inf,minnb=inf;
for(int i=1;i<=n;i++){
a[i-1]=read();
minna=min(minna,a[i-1]);
}
for(int i=1;i<=n;i++){
b[i-1]=read();
minnb=min(minnb,b[i-1]);
}
int ans1=0,ans2=0;
for(int i=0;i<n;i++){
ans1+=minna+b[i];
ans2+=minnb+a[i];
}
cout<<min(ans1,ans2)<<'\n';
//puts(ans>0?"YES":"NO");
//puts(ans>0?"Yes":"No");
}
\(C. Make it Alternating\)
对每个区间的删掉的元素数量统计,首先统计可选择的方案数,然后选择顺序。方案数显然是乘法原理,顺序就是删除的个数的 \(A\) 。
vector<mint>fac(N);
void init(){
fac[0]=1;
for(int i=1;i<=200000;i++){
fac[i]=(mint)i*fac[i-1];
}
}
void solve(){
string s;
cin>>s;
vector<int>vec;
for(int i=0,tmp=0;i<s.size();i++){
if(s[i-1]==s[i]||i==0)tmp++;
else{
vec.push_back(tmp);
tmp=1;
}
if(i==s.size()-1)
vec.push_back(tmp);
}
mint ans=1;
int sum=0;
for(auto x:vec){
if(x-1>0){
sum+=(x-1);
ans*=x;
}
}
cout<<sum<<" "<<(mint)fac[sum]*ans<<'\n';
//puts(ans>0?"YES":"NO");
//puts(ans>0?"Yes":"No");
}
\(D. Sum of XOR Functions\)
这道题的做法也比较有意思。异或有个性质是出现奇数次有贡献,偶数次无贡献。那么对于求所有区间的区间异或和乘上区间长度的和,分别统计二进制位上的出现次数为奇数的区间长度和即可,不过这个统计没有那么显然。若当前和的位置上有 \(1\) ,那么他可以与前面所有位置上为 \(0\) 的位置组成贡献区间,反之相同,详情看代码即可。
void solve(){
int n=read();
vector<int>sum(n+1);
for(int i=1;i<=n;i++){
sum[i]=sum[i-1]^read();
}
mint ans=0;
mint s1[30][2],s2[30][2];
for(int i=0;i<30;i++){
for(int j=0;j<=n;j++){
int x=(sum[j]>>i)&1;
ans+=(s1[i][!x]*(mint)j-s2[i][!x])*(mint)(1<<i);
s1[i][x]+=1;
s2[i][x]+=j;
}
}
cout<<ans<<'\n';
//puts(ans>0?"YES":"NO");
//puts(ans>0?"Yes":"No");
}
\(E. Interactive Game with Coloring\)
首先对于一个节点,如果有多个子节点,可以将通向子节点的边全部赋为一种颜色,通向父节点的边赋为另一种颜色。这样整个树只需要两种颜色。但是若出现节点只有一个子节点,那么若所有这样的节点都是深度都是相同的奇偶形,那么可以统一记录哪个颜色是向上的,否则我们需要引入第三种颜色,构建一个循环寻找父节点,比如出现 \(1,2\) 两种颜色,那么 \(2\) 是通向父节点,出现 \(1,3\) 两种颜色,那么 \(1\) 是通向父节点,出现 \(3,2\) 两种颜色,那么 \(3\) 是通向父节点。同时需要注意到,如果这样的奇偶性不同的特殊节点不在同一颗子树上,我们可以通过改变 \(root\) 节点的边的颜色,转换其子树的边的奇偶性,这样所有节点的奇偶性不同造成的影响将被反转为相同,因为 \(root\) 节点不需要子节点的颜色相同。
int fa[N],dep[N],d[N],maxdep=0,cnt[3];
vector<int>G[N],col(N);
void dfs_dep(int u){
for(auto v:G[u]){
dep[v]=dep[u]+1;
maxdep=max(maxdep,dep[v]);
dfs_dep(v);
}
}
void check(int u){
if(G[u].size()==1) cnt[dep[u]%2]++;
for(auto v:G[u]){
check(v);
}
}
void dfs_col(int u){
for(auto v:G[u]){
col[v]=col[u]^1;
dfs_col(v);
}
}
void solve(){
int n=read();
for(int i=1;i<n;i++){
fa[i]=read()-1;
G[fa[i]].push_back(i);
}
dfs_dep(0);
if(maxdep==1){
cout<<1<<endl;
for(int i=1;i<n;i++){
cout<<1<<' ';
}
cout<<endl;
int op=read(),x=read();
cout<<1<<'\n';
return ;
}
int ok=1;
for(auto i:G[0]){
cnt[0]=cnt[1]=0;
check(i);
if(cnt[1]&&cnt[0]){
ok=0;
break;
}
col[i]=cnt[0]?1:0;
dfs_col(i);
}
int k=0;
if(!ok){
k=3;
cout<<3<<endl;
for(int i=1;i<n;i++){
cout<<dep[i]%3+1<<" ";
}
cout<<endl;
}else{
k=2;
cout<<2<<endl;
for(int i=1;i<n;i++){
cout<<col[i]+1<<" ";
}
cout<<endl;
}
while(true){
int op=read();
if(op==1||op==-1)break;
vector<int>u;
for(int i=0;i<k;i++){
int x=read();
if(x==1)u.push_back(i);
}
int res;
if(u.size()>1){
if(k==2){
res=1;
}else{
if((u[0]+1)%3!=u[1]){
res=u[1]+1;
}else{
res=u[0]+1;
}
}
}else{
res=u[0]+1;
}
cout<<res<<endl;
}
//puts(ans>0?"YES":"NO");
//puts(ans>0?"Yes":"No");
}
\(F. Last Man Standing\)
首先每个人的存活回合是 \(h_i*\frac{a_i}{x}\) 。考虑枚举 \(x\) 。然后如何计算最大值呢。显然的对同一个 \(a_i\) 只有最大的 \(h_i\) 需要考虑。然后每个 \(a_i\) 和 \(h_i\) 能作为最后一个人得倒分数显然至少需要 \({h_i}-{a_i}\) 这样一个 \(pair\) 大于后面的 \(pair\) ,这样记录后缀最大值即可,枚举每个不同的 \(\frac{a_i}{x}\) 就是枚举 \(x\) 的倍数,总体复杂度是调和级数 \(O(log_2n)\) ,别忘了要计算次大值判断最大值是否合法。
void solve(){
int n=read();
vector<int>h(n),a(n);
for(int i=0;i<n;i++){
h[i]=read();
}
map<pair<int,int>,int>id;
for(int i=0;i<n;i++){
a[i]=read();
id[make_pair(h[i],a[i])]=i;
}
vector<array<pair<int,int>,2> >f(N);
for(int i=0;i<n;i++){ //记录每个a[i]的最大值
auto v=make_pair(h[i],a[i]);
for(auto &y:f[a[i]]){
if(v>y){
swap(v,y);
}
}
}
for(int i=N-11;i>=0;i--){ //记录后缀最大值
for(auto v:f[i+1]){
for(auto &y:f[i]){
if(v>y){
swap(v,y);
}
}
}
}
vector<int>ans(n);
for(int x=1;x<=N-10;x++){
int maxx=0,l=0;
for(int i=1;i<=N-10;i+=x){ //枚举倍数
int res=1*(i+x-1)/x*f[i][0].first; //计算最大值的答案
if(res>maxx){
maxx=res;
l=i;
}
}
auto v=f[l][0];
int sec=0;
for(int i=1;i<=N-10;i+=x){
int res=1*(i+x-1)/x*f[i][i<=l&&f[i][0]==v].first;
if(res>sec){
sec=res;
}
}
if(sec<maxx){
int i=id[v];
ans[i]=max(ans[i],maxx-sec);
}
}
for(auto x:ans){
cout<<x<<" ";
}
cout<<'\n';
//puts(ans>0?"Yes":"No");
}

浙公网安备 33010602011771号