A. Showstopper

对于两个序列 a1,a2,,ana_1,\,a_2,\,\cdots,\,a_nb1,b2,,bnb_1,\,b_2,\,\cdots,\,b_n,可以进行任意次操作,每次操作可以将 ai,bi  (1in)a_i,\,b_i\;(1\leqslant i \leqslant n) 进行互换.

问在进行任意次操作后,是否能够满足:

  • an=max(a1,a2,,an)a_n=\max(a_1,\,a_2,\,\cdots,\,a_n)
  • bn=max(b1,b2,,bn)b_n=\max(b_1,\,b_2,\,\cdots,\,b_n)

解题报告

按照题意,若 ai>an  (1i<n)a_i>a_n\;(1\leqslant i<n),则让 ai,bia_i,\,b_i 进行交换. 随后,若 bi>bn  (1i<n)b_i>b_n\;(1\leqslant i <n),则让 ai,bia_i,\,b_i 进行交换.

在进行这些操作之后,检查序列 a,ba,\,b 是否满足题意,若满足则输出 Yes,否则输出 No.

#include<bits/stdc++.h>
using namespace std;
void solve(){
    int n; cin>>n;
    vector<int>a(n+1),b(n+1);
    for(int i=1;i<=n;++i) cin>>a[i];
    for(int i=1;i<=n;++i) cin>>b[i];
    for(int i=1;i<n;++i)
        if(a[i]>a[n]) swap(a[i],b[i]);
    for(int i=1;i<n;++i)
        if(b[i]>b[n]) swap(a[i],b[i]);
    for(int i=1;i<n;++i)
        if(a[i]>a[n] || b[i]>b[n]){
            cout<<"No\n";
            return;
        }
    cout<<"Yes\n";
}
int main(){
    ios::sync_with_stdio(0); cin.tie(0);
    int T; cin>>T;
    while(T--) solve();
    return 0;
}

时间复杂度分析

每组测试数据的时间复杂度为 O(n)O(n).

TAG

#模拟 #暴力

B. Three Sevens

某抽奖活动将会持续 mm 天,第 ii 天会有 nin_i 个人参与抽奖,他们的编号为 ai,1,,ai,nia_{i,1},\,\cdots,\,a_{i,n_i}.

每天都仅有一人获奖,并且第 ii 天获奖的人不能再参加第 i+1mi+1\sim m 天的抽奖.

现在对于给出的每天的参与抽奖的信息,问是否存在一个合法的抽奖活动的获奖名单.

解题报告

lstxlst_x 表示编号为 xx 的人最后一次参与抽奖是第几天,即编号为 xx 的人在第 lstx+1mlst_x+1 \sim m 天都没有再参与抽奖.

这样的人就可能是第 lstxlst_x 天的获奖的人.

检查这 mm 天是否都有这样的人存在即可.

#include<bits/stdc++.h>
using namespace std;
const int N=50000+5;
void solve(){
    int m; cin>>m;
    vector<int>a_lst(N);
    vector a(m,vector<int>());
    for(int i=0;i<m;++i){
        int n; cin>>n;
        while(n--){
            int x; cin>>x;
            a[i].push_back(x);
            a_lst[x]=i;
        }
    }
    vector<int>ans;
    for(int i=0;i<m;++i){
        bool have_answer=0;
        for(auto &x:a[i])
            if(a_lst[x]==i){
                have_answer=1;
                ans.push_back(x);
                break;
            }
        if(!have_answer){
            cout<<"-1\n";
            return;
        }
    }
    for(auto &x:ans)
        cout<<x<<' ';
    cout<<'\n';
}
int main(){
    ios::sync_with_stdio(0); cin.tie(0);
    int T; cin>>T;
    while(T--) solve();
    return 0;
}

时间复杂度分析

每组测试数据的时间复杂度为 O(i=1mni)O\left(\sum\limits_{i=1}^mn_i\right).

TAG

#模拟 #暴力

C. Candy Store

商店里有 nn 种糖果,编号为 1n1 \sim n. 第 ii 种糖果总共有 aia_i 块,每块卖 bib_i 元.

现在对糖果进行装袋销售,第 ii 种糖果每袋装 did_i 块,要求 did_i 能整除 aia_i(即对于同种糖果,要求每袋糖果的块数一样). 这样每袋的售价为 ci=bidic_i=b_i\cdot d_i.

现在将装袋好的糖果按照种类编号依次摆开,开始贴价格标签.

如果相邻的两种糖果,每袋的售价相同,则可以共用一个价格标签.

问使用最少的价格标签数量.

解题报告

考虑对于两种糖果 (ai,bi),  (aj,bj)(a_i,\,b_i),\;(a_j,\,b_j),如果能够找到一个价格标签 cc 让它们共用,则 cc 应该满足:

  • aibi%c=0a_i\cdot b_i \,\%\,c=0
  • ajbj%c=0a_j\cdot b_j \,\%\,c=0
  • c%bi=0c\,\%\,b_i =0
  • c%bj=0c\,\%\,b_j =0

如果满足 c%bi=0c\,\%\,b_i=0aibi%c=0a_i\cdot b_i \,\%\,c=0,则 ai%cbi=0a_i \,\%\,\frac{c}{b_i}=0 是肯定满足的.

即若 x%y=0x\,\%\,y=0,则一定有 xk%yk=0xk\,\%\,yk=0.

即需要满足:

  • ccaibia_i\cdot b_iajbja_j\cdot b_j 的公约数.
  • ccbib_ibjb_j 的公倍数.

进一步地说:

  • cc 能被 gcd(aibi,  ajbj)\gcd(a_i\cdot b_i,\;a_j\cdot b_j) 整除.
  • cc 能整除 lcm(bi,  bj){\rm lcm}(b_i,\;b_j).
  • gcd(aibi,  ajbj)\gcd(a_i\cdot b_i,\;a_j\cdot b_j) 能整除 lcm(bi,  bj){\rm lcm}(b_i,\;b_j).

故如果 lir{aibi}\gcd_{l\leqslant i \leqslant r} \{a_i\cdot b_i\} 能整除 lcmlir{bi}{\rm lcm}_{l\leqslant i \leqslant r}\{b_i\},则说明存在一个价格标签 cc 能够让第 lrl\sim r 种糖果共用.

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
void solve(){
    int n; cin>>n;
    LL GCD=0,LCM=1;
    int ans=1;
    for(int i=1;i<=n;++i){
        LL a,b; cin>>a>>b;
        GCD=gcd(GCD,a*b);
        LCM=lcm(LCM,b);
        if(GCD%LCM){
            ++ans;
            GCD=a*b;
            LCM=b;
        }
    }
    cout<<ans<<'\n';
}
int main(){
    ios::sync_with_stdio(0); cin.tie(0);
    int T; cin>>T;
    while(T--) solve();
    return 0;
}

时间复杂度分析

每组测试数据的时间复杂度约为 O(nlog(aibi))O\big(n\log (a_i\cdot b_i)\big).

TAG

#数学 #数论 #最大公约数GCD

D. Shocking Arrangement

给一个序列 a1,,ana_1,\,\cdots,\,a_n,保证 i=1nai=0\sum\limits_{i=1}^n a_i=0.

现在可以对序列重新排序,要求:

1lrnal++ar<max(a1,,an)min(a1,,an),\max_{1\leqslant l \leqslant r \leqslant n}|a_l+\cdots+a_r|<\max(a_1,\,\cdots,\,a_n)-\min(a_1,\,\cdots,\,a_n),

其中 x|x| 代表 xx 的绝对值.

问重新排序后是否能够满足要求.

解题报告

考虑如何求 1lrnal++ar\max\limits_{1\leqslant l \leqslant r \leqslant n}|a_l+\cdots+a_r|.

考虑前缀和 sumk=i=1kaisum_k=\sum\limits_{i=1}^ka_i,有

1lrnal++ar=max{sum}min{sum}.\max\limits_{1\leqslant l \leqslant r \leqslant n}|a_l+\cdots+a_r|=\max\{sum\}-\min\{sum\}.

只需要保证 sum(min{a},max{a}]sum\in\big(\min\{a\},\max\{a\}\big],就一定有

max{sum}min{sum}<max{a}min{a}.\max\{sum\}-\min\{sum\}<\max\{a\}-\min\{a\}.

设当前重新排序排到了第 ii 个位置,对于前缀和 sumisum_i,有:

  • sumi10sum_{i-1}\leqslant 0,则从序列 aa 中选择一个非负整数作为 aia_i.
  • sumi1>0sum_{i-1}>0,则从序列中选择一个负数作为 aia_i.
  • 可以发现,这样可以保证 min{sum}>min{a}\min\{sum\}>\min\{a\},并且由于 p=1nap=0\sum\limits_{p=1}^na_p=0,所以如上两种情况肯定都能得到满足.

但特别地,若序列 aa 全由 00 组成,此时有 max{a}=min{a}\max\{a\}=\min\{a\},则不论怎么重新排序都不能满足 min{sum}>min{a}\min\{sum\}>\min\{a\},此时题目无解.

#include<bits/stdc++.h>
using namespace std;
void solve(){
    int n; cin>>n;
    vector<int>a(n);
    for(int i=0;i<n;++i) cin>>a[i];
    if(*max_element(a.begin(),a.end())==0){
        cout<<"No\n";
        return;
    }
    queue<int>pos,neg;
    for(int i=0;i<n;++i)
        if(a[i]>=0) pos.push(a[i]);
        else neg.push(a[i]);
    vector<int>ans;
    int sum=0;
    for(int i=0;i<n;++i){
        if(sum<=0){
            ans.push_back(pos.front());
            pos.pop();
        } else {
            ans.push_back(neg.front());
            neg.pop();
        }
        sum+=ans[i];
    }
    cout<<"Yes\n";
    for(auto &x:ans) cout<<x<<' ';
    cout<<'\n';
}
int main(){
    ios::sync_with_stdio(0); cin.tie(0);
    int T; cin>>T;
    while(T--) solve();
    return 0;
}

时间复杂度分析

每组测试数据的时间复杂度为 O(n)O(n).

TAG

#贪心 #数学 #最大子段和