2023牛客暑期多校训练营7

M.Wring Books

问从1到n所有数的数位加起来一共是多少

假设n为1025

我们分别从个位,十位,百位,...考虑

对于个位,1到1025每个数都有个位,所以加1025

对于十位,1到1025中1到9没有十位,所以加1025-9

对于百位,1到1025中1到99没有百位,所以加1025-99

对于千位,1到1025中1到999没有千位,所以加1025-999

AC代码:

#include
#include
#include
#include
#include
#include
#define endl '\n'
using namespace std;
typedef long long ll;
void solve(){
    int x;
    cin>>x;
    string s=to_string(x);
    int len=s.size()-1;
    ll res=x;
    int t=9;
    for(int i=1;i<=len;i++){
        res+=x-t;
        t=t*10+9;
    }
    cout<>t;
    while(t--)
        solve();
    return 0;
}

C.Beautiful Sequence

找到b[i]的最高位的1,由于b[i]=a[i]^a[i+1],又因为数组a非降序,所以a[i]的该位肯定是0(a[i]和a[i+1]的该位一位是0一位是1,又因为数组非降序)

然后根据将b[1],b[2],...b[i-1]全部异或起来,比如说

 2023牛客暑期多校训练营7_第1张图片

b[1],b[2],b[3],b[4],b[5]全部异或起来,然后中间a[2],a[3],a[3],a[4]都被抵消了,只剩下a[1]和a[5]的异或了,然后a[5]的某一位已经确定为0了,所以就能确定a[1]的这一位了

如果a[1]确定了,我们就能通过递推关系确定整个a序列,所以我们的任务就是确定a[1]

对于a[1]没有确定的位,我们就自己填充,具体解释见注释

AC代码:

#include
#include
#include
#include
#include
#include
#include
#define endl '\n'
//#define int long long
using namespace std;
typedef long long ll;
const int N=1e6+10;
int a[N],b[N];
int space[31];
int n,k;
//求x的最高位的1是第几位
inline int highbit(int x) {
    //从2^30开始,即第31位开始,不断左移,如果遇到哪一位为1,就返回是第几位
    for(int t=1<<30,cnt=31; t>0; t>>=1,cnt--) {
        if(x&t) return cnt;
    }
    return -1;
}
void solve() {
    memset(space,0,sizeof space);
    cin>>n>>k;
    for(int i=1; i>b[i];
    for(int i=1; i0; j--) tmp^=b[j];
            tmp&=i;
            a[1]+=tmp;
        }
        //如果第cnt位的space值不等于0,说明第cnt位不能确定,那么就自己填充,确定的位我们已经改变不了了,然后未确定的位我们可以选择填充0还是1
        //那么具体如何填充呢?因为我们要使得字典序是第k小的,所以我们未确定的位就和k(已经减过1了)的二进制对照,从最低位开始,第i次使用k(已经减过1了)的第i低的位进行填充
        //pos表示二进制,pos不断左移,从1到10到100到1000...
        else {
            if(pos>k) continue;//如果已经填充为第k小的了,那么就不用继续填充了,前面补前导0就行了,而每一位本身就是0,所以根本无需操作,直接continue
            if(k&pos) a[1]+=i;//如果k的这一位为1,那么就将a[1]的这一位改为1
            pos<<=1;//pos左移一位
        }
    }
    //pos由于最后多移动了一位,所以我们填充的其实少一位,这也就是为什么要取等号的原因,所以当pos小于等于k时,说明没有填充到第k小,输出-1
    if(pos<=k) {
        cout<<-1<>t;
    while(t--)
        solve();
    return 0;
}

I.We love Strings

k>>1相当于k/2

k>>=1相当于k/=2

按字符串长度进行分类

当字符串长度小于等于20时,直接暴力枚举所有可能的字符串,放入set中,由于set会自动去重,所以只要返回set中的元素个数就行了

当字符串长度大于20时,对于长度为i的所有字符串,枚举所有选与不选这些字符串的二进制串,根据容斥原理算满足的个数(具体解释见注释)

证明见2023牛客暑假多校 C I M 题解 | JorbanS_JorbanS的博客-CSDN博客

容斥原理:

2023牛客暑期多校训练营7_第2张图片 

2023牛客暑期多校训练营7_第3张图片 

AC代码: 

#include
#include
#include
#include
#include
#include
#include
#include
#define endl '\n'
//#define int long long
using namespace std;
typedef long long ll;
const int N=410,mod=998244353;
vectors[N];
setst;
string tmp;
int n;
void dfs(string s,int len,int cur) {
    //s为当前已经生成的字符串
    //cur表示当前填了几个了
    if(s.size()==len) {
        st.insert(s);
        return;
    }
    //tmp是题目所给的字符串,s是我们自己构造的字符串,当前字符为?时,改成0或1,当前字符本来就为0或1时,那么直接就是原来的字符
    if(tmp[cur]=='?') {
        dfs(s+'1',len,cur+1);//始终搜长度为len的字符串
        dfs(s+'0',len,cur+1);
    } else {
        dfs(s+tmp[cur],len,cur+1);
    }
}
void solve() {
    cin>>n;
    for(int i=1; i<=n; i++) {
        string ss;
        cin>>ss;
        int sz=ss.size();//字符串的长度
        s[sz].push_back(ss);//长度相同的字符串都放在一个容器里
    }
    int ans=0;
    //枚举字符串的长度
    for(int i=1; i<=400; i++) {
        if(!s[i].size()) continue;//如果没有长度为i的字符串,那么就continue
        //如果字符串长度小于等于20
        if(i<=20) {
            for(auto ss:s[i]) {
                tmp=ss;
                dfs("",i,0);//从空字符串开始搜,搜所有长度为i的字符串
            }
        }
        //如果字符串长度大于20
        else {
            int num=s[i].size();//长度为i的字符串有几个
            int m=1<>t&1) {
                        cnt++;
                        //遍历长度为i的字符串s[i][t]中的每一个字符s[i][t][tt]
                        for(int tt=0; tt>t;
    while(t--)
        solve();
    return 0;
}

你可能感兴趣的:(2023牛客多校,算法,c++)