2023-8-5模拟赛游记

#A. peop1e 的串串

签到题

/*
 * @Author: 2019yyy
 * @Date: 2023-08-05 09:00:51
 * @LastEditors: 2019yyy
 * @LastEditTime: 2023-08-05 09:12:14
 * @FilePath: \code\codeBiulders\60a7\T1.cpp
 * @Description: 
 * 
 * I love Chtholly forever 
 */
#include<bits/stdc++.h>
using namespace std;
int a[110];
int main(){
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    int T;
    cin>>T;
    while(T--){
        memset(a,0x3f,sizeof(a));
        int n;
        cin>>n;
        string str;
        cin>>str;
        a[str[0]-'a']=1;
        bool flag=false;
        for(int i=1;i<n;i++){
            //cout<<str[i]<<' '<<a[str[i]-'0']<<"\n";
            if(a[str[i]-'a']!=0x3f3f3f3f&&!a[str[i-1]-'a']!=a[str[i]-'a']){
                cout<<"No\n";
                flag=true;
                break;
            }
            a[str[i]-'a']=!a[str[i-1]-'a'];
        }
        if(!flag){
            cout<<"Yes\n";
        }
    }
    return 0;
}

#B. 开平方

我们可以通过打表发现只有对\(4\)取余得2的数不满足条件

具体证明

\[\because y^2−z^2=x \]

\[\therefore x=(y+z)(y-z) \]

\[\because y,z\in Z \therefore y+z,y-z同奇偶 \]

\[\therefore x是奇数或是4的倍数 \]

/*
 * @Author: 2019yyy
 * @Date: 2023-08-05 09:14:22
 * @LastEditors: 2019yyy
 * @LastEditTime: 2023-08-05 09:15:54
 * @FilePath: \code\codeBiulders\60a7\T2.cpp
 * @Description: 
 * 
 * I love Chtholly forever 
 */
#include<bits/stdc++.h>
using namespace std;
int fun(int x){
    return x-x/4-((x%4)>=2);
}
int main(){
    ios::sync_with_stdio(0);
    cin.tie(0);
    cout.tie(0);
    int l,r;
    cin>>l>>r;
    cout<<fun(r)-fun(l-1)<<'\n';
    return 0;
}

#C. 雨

\(dp\)

\(f[i][0]\)表示到第\(i\)个箱子且第\(i\)个箱子上没盖板不会被雨淋的杂志数量的最大值

\(f[i][1]\)表示到第\(i\)个箱子且第\(i\)个箱子上盖板不会被雨淋的杂志数量的最大值

若这个箱子上本来没有板就找上个箱子的最优状态

若转移板子了就考虑\(f[i][0]\)是把板子转移给上一个箱子了,于是在上个箱子没盖板的基础上加上上个箱子的杂志数量

若没转移板子就考虑\(f[i][1]\)是把上个板子的最优状态加上这个箱子的杂志数

/*
 * @Author: 2019yyy
 * @Date: 2023-08-05 09:00:51
 * @LastEditors: 2019yyy
 * @LastEditTime: 2023-08-05 09:12:14
 * @FilePath: \code\codeBiulders\60a7\T1.cpp
 * @Description: 
 * 
 * I love Chtholly forever 
 */
#include<bits/stdc++.h>
using namespace std;
int a[110];
int main(){
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    int T;
    cin>>T;
    while(T--){
        memset(a,0x3f,sizeof(a));
        int n;
        cin>>n;
        string str;
        cin>>str;
        a[str[0]-'a']=1;
        bool flag=false;
        for(int i=1;i<n;i++){
            //cout<<str[i]<<' '<<a[str[i]-'0']<<"\n";
            if(a[str[i]-'a']!=0x3f3f3f3f&&!a[str[i-1]-'a']!=a[str[i]-'a']){
                cout<<"No\n";
                flag=true;
                break;
            }
            a[str[i]-'a']=!a[str[i-1]-'a'];
        }
        if(!flag){
            cout<<"Yes\n";
        }
    }
    return 0;
}

这题还有个贪心做法,就是如果找到一个没盖板子的,就在后面一段盖板子的箱子的区间内找一个杂志数量最少的且小于这个没盖板子的杂志数的箱子,从这个箱子挨个往前递板子

这么说可能会比较抽象,举个例子,如样例的第4组测试数据

4
0111
5 4 5 1

我们发现第一个箱子没盖板子,就在后面区间找到杂志数最少的第四个箱子,后面三块板子都往前移动,形象一点讲其实对中间所有箱子没有影响,只是把杂志数最少的箱子的板子与前面没盖板子的调换了

代码不是我的,是\(2022dyx\)的,膜拜大神

#include <bits/stdc++.h>//2022dyx
using namespace std;
int num, a[500000];
int main() {
    int t;
    scanf("%d", &t);
    while(t--) {
        int n;
        scanf("%d", &n);
        char s[500000];
        scanf("%s", s);
        register int i = 0;
        int ans = 0;
        for (; i < n; ++i) {
            scanf("%d", &a[i]);
            if (s[i] == '1') ans += a[i];
        }
        int lst = 0, mn = 0x3f3f3f3f;
        for (i = 0; i < n; ++i) {
            if (s[i] == '0') {
                if (mn < lst) ans = ans - mn + lst;
                lst = a[i];
                mn = 0x3f3f3f3f;
            } else{
                mn = min(mn, a[i]);
            }
        }
        if (mn < lst) ans = ans - mn + lst;
        printf("%d\n", ans);
    }
}

#D. 异或和

我们先考虑这么一个问题

有一个 \(n\) 个元素的数组 \(a\) ,设\(f(i,j)=a_i \bigoplus a_j\)
现在你要求对于所有的 $1≤i≤j≤n $的 \(f(i,j)\)之和。

由于异或运算是按位异或,可以从二进制入手

由异或的运算性质可知,当两个数不同时,异或的结果为\(1\),而且最后的异或和只与异或结果为\(1\)的位有关,因此只需要统计所有的数某一位上两两异或的结果为\(1\)的个数,然后用个数乘以当前位的权值,相加就得到答案

设某一位为\(0\)\(1\)的个数分别为\(x\),\(y\),则\(x\times y\)就是要统计的结果,之后再相加

理解了上述这个问题过后问题就变成对于\(1\)-\(n\)\(1\)-\(m\)的两个数组,如何快速对每一个二进制位都求出对应的\(x\)\(y\)

关于这个问题我们又可以打表找规律(((

如:

1: 0001

2: 0010

3: 0011

4: 0100

5: 0101

6: 0110

7: 0111

8: 1000

9: 1001

我们会发现,\([1,n]\)中第\(k\)位总共\(1\)的个数就是:\(n \div 2^k \times 2^(k-1)\)

因为如果\(x\) mod \(2^k >=2^(k-1)\) \(x\)的第\(k\)位就是\(1\)

/*
 * @Author: 2019yyy
 * @Date: 2023-08-05 09:42:12
 * @LastEditors: 2019yyy
 * @LastEditTime: 2023-08-05 15:01:28
 * @FilePath: \code\codeBiulders\60a7\T4.cpp
 * @Description: 
 * 
 * I love Chtholly forever 
 */
#include<bits/stdc++.h>
using namespace std;
#define int unsigned long long
const int mod=998244353;
void fun(int n,int a[]){
    for(int i=0;i<=62;i++){
        a[i]=0;
    }
    for(int i=1;(1ULL<<(i-1))<=n;i++){
        a[i]=(n/(1ULL<<i))*(1ULL<<(i-1));
        if(n%(1ULL<<i)>=(1ULL<<(i-1))){
            a[i]=(a[i]+((n%(1ULL<<i))-((1ULL<<(i-1)))+1ULL));
        }
    }
}
int a[110],b[110];
signed main() {
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    int T;
    cin>>T;
    while(T--){
        int n,m;
        cin>>n>>m;
        fun(n,a),fun(m,b);
        int ans=0;
        for(int i=1;i<=62;i++){
            ans=(ans+((1ULL<<(i-1))%mod)*((a[i]%mod)*((m-b[i])%mod)%mod+((n-a[i])%mod)*(b[i]%mod)%mod)%mod)%mod;
        }
        cout<<ans%mod<<'\n';
    }
    return 0;
}
posted @ 2023-10-01 18:35  2019yyy  阅读(17)  评论(0)    收藏  举报