CF每日5题Day4(1400)

发布于:2025-03-30 ⋅ 阅读:(35) ⋅ 点赞:(0)

好困,感觉很累,今天想赶紧写完题早睡。睡眠不足感觉做题都慢了。

1- 1761C 构造

void solve(){
    int n;
    cin>>n;
    vector<vector<int>>a(n+1);
    forr(i,1,n){//保证每个集合不同
        a[i].push_back(i);
    }
    forr(i,1,n){
        string s;
        cin>>s;
        forr(j,1,n){
            if(s[j-1]=='1')a[j].push_back(i);//i是j的子集 j有的i没有
        }
    }
    forr(i,1,n){
        cout<<a[i].size()<<' ';
        for(auto ans:a[i]){
            cout<<ans<<' ';
        }
        cout<<endl;
    }
}

2- 1735C 贪心 模拟

成环问题

题意

  • string s是需要加密的,string t是加密过后的
  • 给string t,找加密前词性最小的string s
  • 字母圆圈的排列可以不按字母表,但是必须包含26个字母
  • string s每个字母 对应在字母表中 出现最早 就是字典序小
  • 总结就是找一个字母圈的映射顺序,让string s最小

代码

数据量不大 可以每次链接的时候判断是否成合法的环

map<char,char>pre;//记录t中对s的映射关系 如果pre[i]=j 那么i from t->j from s
map<char,int>vis;//记录要映射的这个字母有没有用过
int check(char a,char b){//判断 如果a->b形成的环是否合法
    //从a指向b a的映射是b a->b
    int now=(int)b,i=1;
    map<int,int>tp;
    tp[(int)a]=1;//假设已经从a遍历过来到b了
    while (now!=-1)
    {
        // cout<<(char)(now)<<pre.count(now)<<endl;
        if(!pre.count(now))return false;//环断了 还没形成完整的环
        now=(int)pre[(char)now];
        i++;
        if(tp[now]){//成了环
            now=-1;
            break;
        }
    }
    if(now==-1&&i<26)return true;
    else return false;
}
void ans(char x){
    forr(i,0,25){
        char c='a'+i;
        if(c==x||vis[c])continue;
        if(!check(x,c)){//判断链接x和c是否会成不合法的环
        //勇敢链接
            pre[x]=c;
            vis[c]=1;
            break;
        }
    }
}
void solve(){
    pre.clear();
    vis.clear();
    int n;
    string t;
    cin>>n>>t;
    int fg=0;
    forr(i,0,n-1){
        if(!pre.count(t[i])){
            ans(t[i]);
        }
    }
    for(auto c:t){
        cout<<pre[c];
    }cout<<endl;
}

3- 1609C 贪心

  • 总乘积是质数 那肯定是 1 × p r i m e 1\times prime 1×prime的组合
  • 先确定质数的位置 然后再前后跳找 × 1 \times 1 ×1的位置 确定范围 也就确定了 ( i , k ) (i,k) (i,k)
  • 一开始想的是先确定1的位置 但是发现可能会出现都是1的乘积,这样不是质数但是增加了运算量
bool is_prime(int n){
    if(n==1)return false;
    for(int i=2;i*i<=n;i++)
        if(n%i==0)return false;
    return true;
}
void solve(){
    int n,e;cin>>n>>e;
    vector<int>a(n+1);
    vector<int>ps;
    int ans=0;
    forr(i,1,n){
        cin>>a[i];
        if(is_prime(a[i]))ps.push_back(i);//先找素数
    }
    for(auto x:ps){
        int idx=0,mul=1;
        int fr=(x-1)/e,ba=(n-x)/e;
        int f1=0,b1=0;
        forr(k,1,fr){//向前跳
            idx=x-k*e;
            if(a[idx]==1)f1++;
            else break;//跳到不是1的a[i] 再乘它就不是素数了 跳出循环防止tle
        }
        forr(k,1,ba){//向后找
            if(k==0)continue;
            idx=x+k*e;
            if(a[idx]==1)b1++;
            else break;
        }
        ans+=((b1+1)*f1+b1);
    }
    cout<<ans<<endl;
}

4- 988C 模拟 map

使用map优化查找效率

struct ans{
    int x,y;
};
void solve(){
    int k;
    cin>>k;
    vector<int>s(k+1);
    map<int,int>m[k+1];
    map<int,ans>sum;
    forr(i,1,k){
        int n;
        cin>>n;
        forr(j,1,n){
            int aa;cin>>aa;
            s[i]+=aa;
            if(!m[i].count(aa))m[i][aa]=j;//记录每一种数的位置
        }
        
    }
    forr(i,1,k){
        for(auto j:m[i]){
            int now=s[i]-j.first;
            int nx=i,ny=j.second;
            if(sum.count(now)){
                cout<<"YES"<<endl;
                cout<<sum[now].x<<' '<<sum[now].y<<endl;
                cout<<nx<<' '<<ny<<endl;
                return;
            }else{
                sum[now]={nx,ny};
            }
        }
    }
    cout<<"NO"<<endl;
}

5- 1131B 思维

  • 平局 就是找前后两场比赛共同的区间大小
  • 记录上次平局 就是 m i n ( x , y ) min(x,y) min(x,y) 这次仍然是这个平局 去重
void solve(){
    int n;
    cin>>n;
    int px=0,py=0;
    int x,y;
    int ans=0,lst=-1;
    forr(i,1,n){
        cin>>x>>y;
        if(min(x,y)>=max(px,py))ans+=min(x,y)-max(px,py)+1;
        if(max(px,py)==lst)ans--;
        lst=min(x,y);
        px=x,py=y;
    }
    cout<<ans<<endl;
}