二次元音游人

这是一股照亮混沌的令和时代互联网的一道光,给在电子的海洋里冲浪的阿宅们带来笑容

Codeforces 2220

天上天下、唯我独尊
天上天下、唯我独尊

現状原点、結ガ独奏。
现状原点、结作独奏

Codeforces Round 1093 (Div. 2)

A.Blocked

image
直接降序就行,注意不能有重复元素

#include<bits/stdc++.h>
#define int long long
using namespace std;
int n;
const int N=1e5+5;
int a[N];
bool vis[N];
inline void solve(){
    cin>>n;
    for(int i=1;i<=100;i++){
        vis[i]=false;
    }
    bool flag=false;
    for(int i=1;i<=n;i++){
        cin>>a[i];
        if(vis[a[i]]){
            flag=true;
        }
        else{
            vis[a[i]]=true;
        }
    }
    if(flag){
        cout<<"-1\n";
        return;
    }
    sort(a+1,a+n+1,greater<int>());
    for(int i=1;i<=n;i++){
        cout<<a[i]<<" ";
    }
    cout<<'\n';
    return;
}
signed main(void){
    cin.tie(NULL)->sync_with_stdio(false);
    int T;
    cin>>T;
    while(T--){
        solve();
    }
    return 0;
}

B. OIE Excursion

image

如果存在一个长度 \(≥ m\) 的连续等值子数组,则不可能逃脱。这是因为穿越这样的区块至少需要 \(m\) 秒,而每个位置在任何连续的 \(m\) 秒内至少会向 \(0\) 方向移动一次。

否则,逃逸是可能的。我们可以把数组看成连续的等值区块,每个区块的长度都小于 \(m\)。对于每个区块来说,都存在一个小于 \(m\) 的时间窗口,在这个窗口内,没有任何一个位置会看向 \(0\)。由于两个连续的区块具有不同的值,因此它们的危险时刻永远不会重合。

#include<bits/stdc++.h>
#define int long long
using namespace std;
int n,m,x;
const int N=2e5+5;
int a;
inline void solve(){
    cin>>n>>m;
    int c,cnt,mx=1;
    for(int i=1;i<=n;i++){
        cin>>a;
        if(i==1){
            c=a,cnt=1;
        }
        else if(a!=c){
            c=a;
            mx=max(mx,cnt);
            cnt=1;
        }
        else{
            cnt++;
        }
    }
    mx=max(mx,cnt);
    if(mx<m) {
        cout<<"YES\n";
    }
    else{
        cout<<"NO\n";
    }
    
    return;
}
signed main(void){
    cin.tie(NULL)->sync_with_stdio(false);
    int T;
    cin>>T;
    while(T--){
        solve();
    }
    return 0;
}

C. Grid L

image

假设最后是 \(n\times m\) 的网格,则有 \(n\times (m+1)\) 个竖线, \(m \times (n+1)\) 个横线,总共 \(n+m+2nm\) 个线,易得:

\[n+m+2nm=p+2q \]

\[2n+2m+4nm+1=2p+4q+1 \]

\[(2n+1)(2m+1)=2p+4q+1 \]

\[(2n+1)(2m+1)=2p+4q+1 \]

所以化成两个奇数相乘得到 \(tot=2p+4q+1\),于是我们可以枚举 \(tot\) 的奇数因数,得到另一个数,如果也是奇数的话说明满足这个式子。

然后还要满足第二个条件,就是 \(L\) 型可以分成一个横线一个竖线,然后一型的可以补齐,所以需要竖线数和横线数不能超过 \(q\),即:

\[n(m+1)\ge q \]

\[m(n+1)\ge q \]

#include<bits/stdc++.h>
#define int long long
using namespace std;
int n,m,p,q;
const int N=1e5+5;
int a[N];
inline void solve(){
    cin>>p>>q;
    int tot=p+q*2;
    tot*=2;
    tot++;

    for(int i=3;i<=sqrt(tot);i+=2){
        if(tot%i==0){
            int ano=tot/i;
            if(ano&1){
                int tmp1=(i-1)/2,tmp2=(ano-1)/2;
                if(tmp1*(tmp2+1)<q||(tmp1+1)*tmp2<q){
                    continue;
                }
                cout<<tmp1<<" "<<tmp2<<'\n';
                return;
            }
        }
        else{
            continue;
        }
    }
    cout<<"-1\n";
    return;
}
signed main(void){
    cin.tie(NULL)->sync_with_stdio(false);
    int T;
    cin>>T;
    while(T--){
        solve();
    }
    return 0;
}

D2. Unique Values (Hard version)

image

对于任意查询的集合,记 \(S_1\) 是只出现了一次的元素, \(S_2\) 是出现了两次的元素, \(S_3\) 是出现了三次的元素。设返回值是\(J\)

\[S_1+2S_2+3S_3=k\ ,\ S_1=J \]

将两边都模 \(2\):

  • \(S_3=0\) 时:

\[S_1\equiv k \pmod 2 \ ,\ S_1 \equiv J \pmod 2 \]

  • \(S_3=1\) 时:

\[S_1+3S_3 \equiv k \pmod 2 \ ,\ S_1 \equiv J \pmod 2 \]

也就是说我们选取的集合中:

  • 如果包含三个相同元素,那么集合大小 \(k\) 和查询返回值就不相等
  • 如果不包含三个相同元素,那么集合大小 \(k\) 和查询返回值就相等

所以使用二分先从区间 \([1,n]\) 中找到区间 \([1,r_1]\) 包含三个元素。

然后第二次二分就从区间 \([1,r_1-1]\cup r_1\) 中筛出区间 \([1,r_2]\cup r_1\) 包含三个元素。

最后第三次二分就从区间 $[1,r_2-1]\cup r_1 \cup $ r_2中筛出区间 \([1,r_3]\cup r_1 \cup r_2\) 包含三个元素。

#include<bits/stdc++.h>
#define int long long
using namespace std;
int n;
const int N=1e5+5;
inline int query1(int k){
    cout<<"? "<<k<<" ";
    for(int i=1;i<=k;i++){
        cout<<i<<" ";
    }
    cout<<endl;
    int res;
    cin>>res;
    return res;
}
inline int query2(int k,int Ans1){
    cout<<"? "<<k+1<<" ";
    for(int i=1;i<=k;i++){
        cout<<i<<" ";
    }
    cout<<Ans1<<endl;
    int res;
    cin>>res;
    return res;

}
inline int query3(int k,int Ans1,int Ans2){
    cout<<"? "<<k+2<<" ";
    for(int i=1;i<=k;i++){
        cout<<i<<" ";
    }
    cout<<Ans1<<" "<<Ans2<<endl;
    int res;
    cin>>res;
    return res;

}
inline void solve(){
    cin>>n;
    int l=1,r=2*n+1,ans1=0;
    while(l<=r){
        int mid=(l+r)>>1;
        int res=query1(mid);
        if((res&1)==(mid&1)){
            l=mid+1;
        }
        else{
            ans1=mid;
            r=mid-1;
        }
    }
    l=1,r=ans1-1;
    int ans2=0;
    while(l<=r){
        int mid=(l+r)>>1;
        int res=query2(mid,ans1);
        if((res&1)==((mid+1)&1)){
            l=mid+1;
        }
        else{
            ans2=mid;
            r=mid-1;
        }
    }
    l=1,r=ans2-1;
    int ans3=0;
    while(l<=r){
        int mid=(l+r)>>1;
        int res=query3(mid,ans1,ans2);
        if((res&1)==((mid+2)&1)){
            l=mid+1;
        }
        else{
            ans3=mid;
            r=mid-1;
        }
    }
    cout<<"! "<<ans1<<" "<<ans2<<" "<<ans3<<endl;

}
signed main(void){
    cin.tie(NULL)->sync_with_stdio(false);
    int T;
    cin>>T;
    while(T--){
        solve();
    }
    return 0;
}

要注意第二分的大小要加上 \(1\),第三次二分的大小要加上 \(2\)

posted @ 2026-04-25 17:38  超绝最可爱天使酱  阅读(19)  评论(0)    收藏  举报