A.幽幽子想吃东西

每n吨获得a点满意度,最后判定一下n顿是否大于b吨决定是否要减去c的满意度即可

void solve(){
    int a,b,c,n;
    cin>>a>>b>>c>>n;
    int ans=n*a-(n<=b)*c;
    cout<<ans<<endl;
}

B.幽幽子想吃东西

由于食材只能存2天,对于每一天考虑优先使用前一天剩下的食材,如果前一天不够吃再使用当天食材,这样都不能满足就回答No即可.

void solve(){
    int n,x;
    cin>>n>>x;
    vector<int>a(n+1);
    for(int i=1;i<=n;i++) cin>>a[i];
    for(int i=1;i<=n;i++){
        if(i>=2&&a[i-1]>=x) continue;
        else if(i>=2){
            int cur=x-a[i-1];//当天还需要的食材
            if(a[i]<cur){
                cout<<"No"<<endl;
                return;
            }
            a[i]-=cur;
        }
        else if(i==1){
            if(a[i]<x){
                cout<<"No"<<endl;
                return;
            }
        }
    }
    cout<<"Yes"<<endl;
}

C.三妖精say subsequence !!!

先拿桶记录一下每种字符在原序列中的个数,

暴力枚举前两种字符有几种选择,然后可以用所有字符数量减去前两种字符数量直接计算得出最后一种字符所有可能

最后答案就是 ,其中 表示第 种字符在原始串中出现次数,表示原始串的长度

void solve(){
    int n;cin>>n;
    string s;cin>>s;
    vector<ll>mp(26);
    for(int i=1;i<=n;i++) mp[s[i-1]-'a']++;
 
    ll ans=0;
    for(int i=0;i<26;i++){
        for(int j=0;j<26;j++){
            if(i==j) continue;
            ans+=mp[i]*mp[j]%mod*(n-mp[i]-mp[j])%mod;
            ans%=mod;
        }
    }
    cout<<ans<<endl;
}

D.恋恋的01串大冒险

首先你可以注意到操作次数随最长存在天数变大而单调递增

可以预处理出一个数组记录存在天至少需要几次操作

最后回答询问的时候再使用双指针或二分快速查找出至少需要几次操作存在天.

Solve by binary search

void solve(){
    int n,k;cin>>n>>k;
    string s;cin>>s;
    s="&"+s;
    int cnt=0,op=0;
    vector<int>ans(n+1);//大于等于i天至少需要几次操作
    //单调不减的一个操作序列,满足二分性质
    for(int i=1;i<=n;i++){
        if(s[i]=='0') cnt++;
        else if(s[i]=='1') cnt=0;
        if(cnt==k) {
            op++;
            cnt=0;
        }
        ans[i]=op;
    }
    for(int op=0;op<=n;op++){
        auto it=upper_bound(ans.begin(),ans.end(),op);
        cout<<prev(it)-ans.begin()<<' ';
    }
    cout<<endl;
}

solve by two-pointer

void solve(){
    int n,k;cin>>n>>k;
    string s;cin>>s;
    s="&"+s;
    int cnt=0,op=0;
    vector<int>ans(n+1);//大于等于i天至少需要几次操作
    //单调不减的一个操作序列,满足二分性质
    for(int i=1;i<=n;i++){
        if(s[i]=='0') cnt++;
        else if(s[i]=='1') cnt=0;
        if(cnt==k) {
            op++;
            cnt=0;
        }
        ans[i]=op;
    }
    int res=0;
    for(int op=0;op<=n;op++){
        while(res<=n&&ans[res]<=op) res++;
        cout<<res-1<<' ';
    }
    cout<<endl;
}

E.the world

比较吃细节的小模拟题目

写的比较丑陋不建议学习

考虑到每个单元格有几种状态:

1.当前是奇数偶数秒访问单元格

2.单元格是否使用过时停操作

因此用一个三维数组标记每个单元格访问状态:第三维大小开0~4

分别标记状态:

0.没使用时停当前是偶数秒访问

1.没使用时停当前是奇数秒访问

2.使用过时停当前是偶数秒访问

3.使用过时停当前是奇数秒访问

数组中某个状态被重复访问过后直接跳过即可

可以转移的有且仅有一下几种状态:

未使用过时停(或使用过时停),下一秒是奇数,奇数不存在幽灵,考虑优先不使用时停

未使用过时停(或使用过时停),下一秒是偶数,偶数不存在幽灵,考虑优先不使用时停

未使用过时停,下一秒是奇数,奇数秒存在幽灵,偶数秒不存在幽灵,使用时停进入下一个状态

未使用过时停,下一秒是奇数,偶数秒存在幽灵,奇数秒不存在幽灵,使用时停进入下一个状态

然后用朴素暴力模拟状态转移即可

#include<bits/stdc++.h>
using namespace std;
#define endl '\n'
typedef long long ll;
struct node{
    int x,y,t;
    int used;//当前是否已经使用了时停操作
};
void solve(){
    int n,m,k;cin>>n>>m>>k;
    set<pair<int,int>>even,odd;//存放幽灵,任意时刻不能触碰
    vector vis(n+1,vector<array<int,4>>(m+1));
    vector a(n+1,vector<int>(m+1));
    for(int i=1;i<=k;i++){
        int x1,y1,x2,y2;
        cin>>x1>>y1>>x2>>y2;
        odd.emplace(x1,y1);
        even.emplace(x2,y2);
    }
    queue<node>Q;
    Q.push({1,1,1,0});
    vis[1][1][1]=1;
    while(!Q.empty()){
        int x=Q.front().x;
        int y=Q.front().y;
        int t=Q.front().t;
        int used=Q.front().used;
        if(x==n&&y==m){
            cout<<t-1<<endl;
            return;
        }
        Q.pop();
        for(int i=0;i<4;i++){
            int fx=x,fy=y,ft=t+1;
            if(i==0) fx++;
            if(i==1) fx--;
            if(i==2) fy++;
            if(i==3) fy--;//枚举下一个状态
            if(fx<1||fx>n) continue;
            if(fy<1||fy>m) continue;
            if(used){
                if(vis[fx][fy][ft%2+2]) continue;
                if(odd.count({fx,fy})&&ft%2) continue;
                if(even.count({fx,fy})&&ft%2==0) continue;
                vis[fx][fy][ft%2+2]=1;
                Q.push({fx,fy,ft,used});
            }
            else{
                if(vis[fx][fy][ft%2]) continue;
                if(!odd.count({fx,fy})&&ft%2){
                    vis[fx][fy][ft%2]=1;
                    Q.push({fx,fy,ft,0});
                }
                if(!even.count({fx,fy})&&ft%2==0){
                    vis[fx][fy][ft%2]=1;
                    Q.push({fx,fy,ft,0});
                }
                if(vis[fx][fy][ft%2+2]) continue;
                if(odd.count({fx,fy})&&ft%2&&!even.count({fx,fy})) {
                    vis[fx][fy][ft%2+2]=1;
                    Q.push({fx,fy,ft,1});
                }
                if(even.count({fx,fy})&&ft%2==0&&!odd.count({fx,fy})) {
                    vis[fx][fy][ft%2+2]=1;
                    Q.push({fx,fy,ft,1});
                }
            }
        }
    }
    cout<<-1<<endl;
}
int main(){
    cin.tie(0)->ios::sync_with_stdio(false);
    solve();
    return 0;
}

F.永远亭的小游戏(续)

子序列之积是完全平方数,这是个很神秘的性质

稍加观察发现的大小十分小,[0,100]范围内的素数个数仅有25个

的大小十分小,且[0,100]范围内的素数个数仅有25个

因此考虑使用唯一分解定理

一个完全平方数表示为 ,当且仅当 幂次都是偶数才成立

由此题目转化为了求区间中选若干个数,他们对25个素数的唯一分解定理结果的幂次之和为偶数

由于只关心奇偶性,且幂次和的奇偶性取值只有两种[0,1],钦定0表示偶数,1表示奇数

考虑把每个数压成一个25位地二进制数,

每一位代表一个素数的幂次是奇数还是偶数,

就是询问区间[l,r]中是否存在若干个二进制数其异或和为0.

其实这等价于区间上找最小异或和,然后如果是 0,回答 ,否则回答

然后若干次询问中最小异或和其实是前缀线性基可以完美实现的

因此力大砖飞地使用维护前缀线性基解决此题...

线性基的详细用法

//Stop learning useless algorithms, go and solve some problems, learn how to use binary search.
#include<bits/stdc++.h>
using namespace std;
#define endl '\n'
typedef long long ll;
vector<int>p;
vector<char>isp;
vector<vector<int>>fac;
const int N=2e5+5;
const int INF=114514;
int mp[105];
void Init(int n){
    isp.assign(n,1);
    fac.resize(n);
    isp[0]=isp[1]=0;
    for(int i=2;i<n;i++){
        if(isp[i]) p.push_back(i);
        for(int j=i*2;j<n;j+=i) isp[j]=0;
    }
    int idx=0;
    for(int x:p){
        mp[x]=idx;
        idx++;
    }
}
struct PLB{
    int d[N][32];// 前缀线性基(32位整数)
    int pos[N][32];// 每个基底最后一次修改的位置(插入顺序)
    int cnt[N];// cnt[num]:插入第num个元素后,[1,num]的总元素个数(即num)
    int num;// 当前插入的元素个数(线性基版本号)
    const int INF = INT_MAX; // 无最小异或值时返回的INF(32位整数最大值)
    PLB(){
        memset(d, 0, sizeof(d));
        memset(pos, 0, sizeof(pos));
        memset(cnt, 0, sizeof(cnt));
        num = 0;
    }
    void clear(){
        memset(d, 0, sizeof(d));
        memset(pos, 0, sizeof(pos));
        memset(cnt, 0, sizeof(cnt));
        num = 0;
    }
    void add(int x){
        num++;
        for(int i=0; i<32; i++){
            d[num][i] = d[num-1][i];
            pos[num][i] = pos[num-1][i];
        }
        cnt[num] = cnt[num-1] + 1; 
        int P = num; 
        for(int i=31; i>=0; i--){
            if((x >> i) & 1){
                if(d[num][i]){
                    if(pos[num][i] < P){
                        swap(pos[num][i], P);
                        swap(d[num][i], x);
                    }
                    x ^= d[num][i];
                }
                else{
                    d[num][i] = x;
                    pos[num][i] = P;
                    break;
                }
            }
        }
    }
    int queryMax(int l, int r){
        int res = 0;
        for (int i=31; i>=0; i--){
            if(pos[r][i] >= l && (res ^ d[r][i]) > res){
                res ^= d[r][i];
            }
        }
        return res;
    }
    int queryMin(int l, int r) {
        int range_cnt = cnt[r] - cnt[l-1]; 
        if(range_cnt == 0) return INF; 
        int basis_size = 0;
        for(int i=0; i<32; i++){
            if(pos[r][i] >= l && d[r][i] != 0){
                basis_size++;
            }
        }
        if(basis_size < range_cnt){
            return 0;
        }
        for(int i=0; i<32; i++){
            if(pos[r][i] >= l && d[r][i] != 0){
                return d[r][i];
            }
        }
        return INF;
    }
};//搬来的前缀线性基板子...
void solve(){
    int n,q;cin>>n>>q;
    vector<int>a(n+1);
    vector<int>b(n+1);
    PLB lb;
    for(int i=1;i<=n;i++) {
        cin>>a[i];
        for(int j=2;j<=a[i]/j;j++){
            int cnt=0;
            while(a[i]%j==0){
                a[i]/=j;
                cnt++;
            }
            if(cnt%2) b[i]|=(1<<mp[j]);
        }
        if(a[i]>1) b[i]|=(1<<mp[a[i]]);
        lb.add(b[i]);
    }//压成一个25位的二进制数
    while(q--){
        int l,r;cin>>l>>r;
        if(lb.queryMin(l,r)) cout<<"No"<<endl;
        else cout<<"Yes"<<endl;
    }
}
int main(){
    cin.tie(0)->ios::sync_with_stdio(false);
    Init(101);
    solve();
    return 0;
}

F过的比E多感觉有点怪了...怎么大家都会xxj