winter week3 day1

2024牛客寒假算法基础集训营2

ATokitsukaze and Bracelet

#include<bits/stdc++.h>
using namespace std;
#define int long long
//#define int __int128
#define double long double
typedef pair<int,int>PII;
typedef pair<string,int>PSI;
typedef pair<string,string>PSS;
const int N=100+5,INF=0x3f3f3f3f,Mod=1e9+7,mod=998244353;
const int MAXN=1e8+5;
const double eps=1e-12;
const int dx[4]={-1,1,0,0};
const int dy[4]={0,0,-1,1};



void solve() {
    int a,b,c;
    cin>>a>>b>>c;
    int ans=0;
    if(a==150)ans++;
    else if(a==200)ans+=2;
    if(b>=34&&b<=40)ans+=1;
    else if(b==45)ans+=2;
    if(c>=34&&c<=40)ans+=1;
    else if(c==45)ans+=2;
    cout<<ans<<'\n';
}

signed main(){
    ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
    int t=1;
    cin>>t;
    while(t--){
        solve();
    }
    return 0;
}
View Code

 

Tokitsukaze and Cats

思路:枚举,看猫的4个方向有多少没有围栏

#include<bits/stdc++.h>
using namespace std;
#define int long long
//#define int __int128
#define double long double
typedef pair<int,int>PII;
typedef pair<string,int>PSI;
typedef pair<string,string>PSS;
const int N=100+5,INF=0x3f3f3f3f,Mod=1e9+7,mod=998244353;
const int MAXN=1e8+5;
const double eps=1e-12;
const int dx[4]={-1,1,0,0};
const int dy[4]={0,0,-1,1};



void solve() {
    int n,m,k;
    cin>>n>>m>>k;
    vector<vector<int>>ve(n+2,vector<int>(m+2));
//    vector<PII>g(k);
    int ans=0;
    for(int i=0;i<k;++i){
        int u,v;
        cin>>u>>v;
        ve[u][v]=1;
        int c=0;
        for(int j=0;j<4;++j){
            int x=u+dx[j],y=v+dy[j];
            if(ve[x][y]==0)c++;
        }
        ans+=c;
    }
    cout<<ans;
}

signed main(){
    ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
    int t=1;
//    cin>>t;
    while(t--){
        solve();
    }
    return 0;
}
View Code

 

CTokitsukaze and Min-Max XOR

思路:求的是子序列的贡献,那顺序就不限制,并且有关最大最小值的,首先把序列排序。

这里还是常用的方法,看最大最小值的贡献,若最小值最大值为a[i]和a[j],那这对数的贡献为2j-i-1

若要枚举ij,复杂度n2的显然不行,这里考虑枚举j,然后logn的找到i满足a[i]^a[j]<=k,显然可以用字典树存二进制

对于查找,首先枚举a[j]和k的同位二进制(从高位开始)。若k当前位为1,那么a[i]和a[j]的当前位可以相同或不同,如果相同:说明异或后当前位为0,那么该位后面可以为任意情况,这个时候直接统计子树的值;如果不同:那继续往下一位找,若已经到最后一位了(即叶子节点)直接统计叶子节点的值。若k当前位为0,说明a[i]和a[j]的当前位必须要相同,同样的继续往下一位找

对于每个j的贡献为2j-i-1,可以看作2j-1/2i,那么字典树存的值其实可以为1/2i,这里用逆元求就好了

#include<bits/stdc++.h>
using namespace std;
#define int long long
//#define int __int128
#define double long double
typedef pair<int,int>PII;
typedef pair<string,int>PSI;
typedef pair<string,string>PSS;
const int N=5e5+5,INF=0x3f3f3f3f,Mod=1e9+7,mod=998244353;
const int MAXN=1e8+5;
const double eps=1e-12;
const int dx[4]={-1,1,0,0};
const int dy[4]={0,0,-1,1};

struct E{
    int val;
    int son[2];
};
int n,k,idx;
vector<E>tr;
void insert(int val,int x){
    int u=1;
    for(int i=30;i>=0;--i){
        int s=(x>>i)&1;
        if(tr[u].son[s]==0)tr[u].son[s]=++idx;
        u=tr[u].son[s];
        tr[u].val=(tr[u].val+val)%Mod;
    }
}

int get(int x){
    int u=1;
    int res=0;
    for(int i=30;i>=0;--i){
        int s=(x>>i)&1,m=(k>>i)&1;
        if(m){
            if(tr[u].son[s])res=(res+tr[tr[u].son[s]].val)%Mod;
            u=tr[u].son[s^1];
        }else u=tr[u].son[s];
    }
    res=(res+tr[u].val)%Mod;
    return res;
}
int ksm(int a,int b){
    int res=1;
    while(b){
        if(b&1)res=res*a%Mod;
        b>>=1;
        a=a*a%Mod;
    }
    return res;
}
void solve() {
    cin>>n>>k;
    tr=vector<E>(n*32,{0,{0,0}});
    idx=1;
    vector<int>a(n+1);
    for(int i=1;i<=n;++i){
        cin>>a[i];
    }
    sort(a.begin()+1,a.end());
    int ans=1;
    for(int i=2;i<=n;++i){
        int s=ksm(2,i-1);
        insert(ksm(s,Mod-2),a[i-1]);
        ans=(ans+1+get(a[i])*s%Mod)%Mod;
    }
    cout<<ans<<'\n';
}
signed main(){
    ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
    int t=1;
    cin>>t;
//    init();
    while(t--){
        solve();
    }
    return 0;
}
View Code

 

 DTokitsukaze and Slash Draw

思路:由于nm范围不大,可以操作每个位置使用每种卡片,跑最短路即可,就是求从0到n-k(位置从上到下为0、n-1、...2、1)

#include<bits/stdc++.h>
using namespace std;
#define int long long
//#define int __int128
#define double long double
typedef pair<int,int>PII;
typedef pair<string,int>PSI;
typedef pair<string,string>PSS;
const int N=1e5+5,INF=0x3f3f3f3f,Mod=1e9+7,mod=998244353;
const int MAXN=1e8+5;
const double eps=1e-12;
const int dx[4]={-1,1,0,0};
const int dy[4]={0,0,-1,1};


void solve() {
    int n,m,k;
    cin>>n>>m>>k;
    vector<vector<PII>>g(n);
    vector<PII>ve(m);
    vector<int>dis(n,1e17),vis(n);
    for(int i=0;i<m;++i)cin>>ve[i].first>>ve[i].second;
    for(int i=0;i<n;++i){
        for(int j=0;j<m;++j){
            int a=ve[j].first,b=ve[j].second;
            int to=(i+a)%n;
            g[i].push_back({to,b});
        }
    }
    dis[0]=0;
    priority_queue<PII,vector<PII>,greater<PII>>q;
    q.push({dis[0],0});
    while(q.size()){
        auto t=q.top();
        q.pop();
        int u=t.second,dist=t.first;
        if(vis[u])continue;
        vis[u]=1;
        for(auto [v,w]:g[u]){
            if(w+dist<dis[v]){
                dis[v]=w+dist;
                q.push({dis[v],v});
            }
        }
    }
    if(dis[n-k]==1e17)cout<<"-1\n";
    else cout<<dis[n-k]<<'\n';
}
signed main(){
    ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
    int t=1;
    cin>>t;
//    init();
    while(t--){
        solve();
    }
    return 0;
}
View Code

 

ETokitsukaze and Eliminate (easy)

思路:同hard

#include<bits/stdc++.h>
using namespace std;
#define int long long
//#define int __int128
#define double long double
typedef pair<int,int>PII;
typedef pair<string,int>PSI;
typedef pair<string,string>PSS;
const int N=100+5,INF=0x3f3f3f3f,Mod=1e9+7,mod=998244353;
const int MAXN=1e8+5;
const double eps=1e-12;
const int dx[4]={-1,1,0,0};
const int dy[4]={0,0,-1,1};



void solve() {
    int n;
    cin>>n;
    vector<int>ve(n);
    for(int i=0;i<n;++i){
        cin>>ve[i];
    }
    int ans=0;
    for(int i=n-1;i>=0;--i){
        int c=0,r=ve[i];
        while(i>=0&&ve[i]==r)i--,c++;
        if(i==-1)ans+=c;
        else ans++;

    }
    cout<<ans<<'\n';
}

signed main(){
    ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
    int t=1;
    cin>>t;
    while(t--){
        solve();
    }
    return 0;
}
View Code

 

FTokitsukaze and Eliminate (hard)

思路:从后往前枚举,找到要操作的颜色。其实就是统计每个颜色的最后一个的位置的最小值即为操作的颜色,再更新每个颜色的最后一个的位置

#include<bits/stdc++.h>
using namespace std;
#define int long long
//#define int __int128
#define double long double
typedef pair<int,int>PII;
typedef pair<string,int>PSI;
typedef pair<string,string>PSS;
const int N=100+5,INF=0x3f3f3f3f,Mod=1e9+7,mod=998244353;
const int MAXN=1e8+5;
const double eps=1e-12;
const int dx[4]={-1,1,0,0};
const int dy[4]={0,0,-1,1};



void solve() {
    int n;
    cin>>n;
    vector<int>ve(n+1),l(n+1),st(n+1);
    for(int i=1;i<=n;++i){
        cin>>ve[i];
        l[i]=st[ve[i]];
        st[ve[i]]=i;
    }
    vector<int>now;
    st=vector<int>(n+1,0);
    int mi=n;
    for(int i=n;i>=1;--i){
        if(!st[ve[i]])now.push_back(i),mi=i;
        st[ve[i]]=1;
    }
    int ans=0;
    while(mi>0){
        ans++;
        if(mi==1)break;
        int s=n;
        vector<int>p;
        for(auto &v:now){
            if(v==0)continue;
            while(v>=mi&&v!=0)v=l[v];
            if(v!=0){
                s=min(s,v);
                p.push_back(v);
            }
        }
        mi=s;
        now=p;
    }
    cout<<ans<<'\n';
}

signed main(){
    ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
    int t=1;
    cin>>t;
    while(t--){
        solve();
    }
    return 0;
}
View Code

 

GTokitsukaze and Power Battle (easy)

思路:对于区间[l,r],要选取两个区间[i,x]和[x,j],使得f[x]=sum[i,x]-sum[x+1,j]最大,由于都为正数,那第一个区间的数要尽可能多,第二个区间的数尽可能少,所以第二个区间只有一个数、第一个区间的左边界为l且个数多是最优的。那么j就从r往前枚举,i就为l,且x+1等于j,满足i<j<=r。

如果暴力枚举所有j肯定会T,由于f[j] = sum[l,j-1]-a[j],看下f[j-1] = sum[l,j-2] - a[j-1] = f[j] - 2a[j-1] + a[j],要是答案更优需满足f[j-1]>f[j],即a[j-1]<a[j]/2,由于a的范围为1e9,那么j枚举不超过31次,就可以树状数组直接枚举答案了

--------------

还有个思路,还是看这个f[j] = sum[l,j-1]-a[j],因为l是定的,那么其实f[j]=sum[1,j-1]-a[j]-sum[1,l-1],枚举的所有j都是要减去sum[1,l-1],其实就对sum[1,j-1]-a[j]用线段树维护区间最大值就可以O1求答案了

对于单点修改x、y,求前缀和的直接用树状数组维护;求区间最大的线段树,单点修改只对x及之后的位置影响,由sum[1,j-1]-a[j],对位置x,其实就是加回原来的a[j]再减去修改的y,为a[j]-y;对位置x+1到n,就是减去原来的a[j]再加上修改的y,为y-a[j],这里用区间修改即可

 

#include<bits/stdc++.h>
using namespace std;
#define int long long
//#define int __int128
#define double long double
typedef pair<int,int>PII;
typedef pair<string,int>PSI;
typedef pair<string,string>PSS;
const int N=1e3+5,INF=0x3f3f3f3f,Mod=1e9+7,mod=998244353;
const int MAXN=1e8+5;
const double eps=1e-12;
const int dx[4]={-1,1,0,0};
const int dy[4]={0,0,-1,1};

vector<int>c;
int n;
int lowbit(int x){
    return x&-x;
}

int getsum(int x){//a[1]..a[x]的和
    int ans=0;
    while(x>0){
        ans+=c[x];
        x-=lowbit(x);
    }
    return ans;
}
int get(int l,int r){
    return getsum(r)-getsum(l-1);
}
void add(int x,int k){
    while(x<=n){
        c[x]+=k;
        x+=lowbit(x);
    }
}
void solve() {
    cin>>n;
    int q;
    cin>>q;
    c=vector<int>(n+5,0);
    for(int i=1;i<=n;++i){
        int x;
        cin>>x;
        add(i,x);
    }
    while(q--){
        int op,l,r;
        cin>>op>>l>>r;
        if(op==1){
            int s= r-get(l,l);
            add(l,s);
        }else{
            int s= get(l,r);
            int ans=-INF;
            for(int i=r;i>l;--i){
                int rr= get(i,i);
                s-=rr;
                if(s<=ans)break;
                int x=s-rr;
                ans=max(ans,x);
            }
            cout<<ans<<'\n';
        }
    }
}
signed main(){
    ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
    int t=1;
    cin>>t;
//    init();
    while(t--){
        solve();
    }
    return 0;
}
View Code
#include<bits/stdc++.h>
using namespace std;
#define int long long
//#define int __int128
#define double long double
typedef pair<int,int>PII;
typedef pair<string,int>PSI;
typedef pair<string,string>PSS;
const int N=5e5+5,INF=0x3f3f3f3f,Mod=1e9+7,mod=998244353;
const int MAXN=1e8+5;
const double eps=1e-12;
const int dx[4]={-1,1,0,0};
const int dy[4]={0,0,-1,1};
vector<int>c;
int n;//每个数的值
int lowbit(int x){
    return x&-x;
}
int getsum(int x){//a[1]..a[x]的和
    int ans=0;
    while(x>0){
        ans+=c[x];
        x-=lowbit(x);
    }
    return ans;
}
void add(int x,int k){
    while(x<=n){
        c[x]+=k;
        x+=lowbit(x);
    }
}

struct Node{
    int l,r;
    int ma;
    int add;//懒标记
};
vector<int>w;
vector<Node>tr;

//pushup
void pushup(int u){
    tr[u].ma=max(tr[u<<1].ma,tr[u<<1|1].ma);
}

//pushdown:除建树外,分裂都需要用
void pushdown(int u){
    Node &root=tr[u],&l=tr[u<<1],&r=tr[u<<1|1];
    l.add+=root.add,l.ma+=root.add;
    r.add+=root.add,r.ma+=root.add;
    root.add=0;
}

//建树
void build(int u,int l,int r){
    if(l==r)tr[u]={l,r,getsum(l-1)-w[l],0};
    else{
        tr[u]={l,r,0,0};
        int mid=l+r>>1;
        build(u<<1,l,mid),build(u<<1|1,mid+1,r);
        pushup(u);
    }
};

//区间修改:区间[l,r]加d
void modify(int u,int l,int r,int d){
    if(tr[u].l>=l&&tr[u].r<=r){
        tr[u].ma+=d;
        tr[u].add+=d;
    }
    else{
        pushdown(u);
        int mid=tr[u].l+tr[u].r>>1;
        if(l<=mid)modify(u<<1,l,r,d);
        if(r>mid)modify(u<<1|1,l,r,d);
        pushup(u);
    }
}

//求[l,r]区间和
int query(int u,int l,int r){
    if(tr[u].l>=l&&tr[u].r<=r)return tr[u].ma;
    else if(r<tr[u].l||tr[u].r<l)return -1e18;
    else{
        pushdown(u);
        return max(query(u<<1,l,r),query(u<<1|1,l,r));
    }
}

void solve() {
    cin>>n;
    int q;
    cin>>q;
    tr=vector<Node>(4*n+5);
    c=w=vector<int>(n+5,0);
    for(int i=1;i<=n;++i) {
        cin >> w[i];
        add(i,w[i]);
    }
    build(1,1,n);
    while(q--){
        int op,l,r;
        cin>>op>>l>>r;
        if(op==1){
            modify(1,l,l,w[l]-r);
            if(l<n)modify(1,l+1,n,r-w[l]);
            add(l,r-w[l]);
            w[l]=r;
        }else{
            cout<<query(1,l+1,r)- getsum(l-1)<<'\n';
        }
    }
}
signed main(){
    ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
    int t=1;
    cin>>t;
//    init();
    while(t--){
        solve();
    }
    return 0;
}
View Code

 

 ITokitsukaze and Short Path (plus)

思路:由权值计算式子可以看出路径长度越长权值越大,那么dist(i,j)最小即为i到j

#include<bits/stdc++.h>
using namespace std;
#define int long long
//#define int __int128
#define double long double
typedef pair<int,int>PII;
typedef pair<string,int>PSI;
typedef pair<string,string>PSS;
const int N=100+5,INF=0x3f3f3f3f,Mod=1e9+7,mod=998244353;
const int MAXN=1e8+5;
const double eps=1e-12;
const int dx[4]={-1,1,0,0};
const int dy[4]={0,0,-1,1};



void solve() {
    int n,ans=0;
    cin>>n;
    vector<int>ve(n+1),pre(n+1);
    for(int i=1;i<=n;++i){
        cin>>ve[i];
        ans+=ve[i]*(2*n-2);
    }
    sort(ve.begin()+1,ve.end());
    for(int i=1;i<=n;++i)pre[i]=pre[i-1]+ve[i];
    for(int i=1;i<=n;++i){
        ans+=pre[n]-pre[i]-(n-i)*ve[i]+(i-1)*ve[i]-pre[i-1];
    }
    cout<<ans<<'\n';
}

signed main(){
    ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
    int t=1;
    cin>>t;
    while(t--){
        solve();
    }
    return 0;
}
View Code

 

JTokitsukaze and Short Path (minus)

思路:由权值计算式子可以看出wij为2*min(ai,aj),那么dist(i,j)有两种情况,一种为2*min(ai,aj),另一种为找到权值最小的点q,dist(i,j)= dist(i,q)+ dist(q,j)=4*aq,取较小值即可

#include<bits/stdc++.h>
using namespace std;
#define int long long
//#define int __int128
#define double long double
typedef pair<int,int>PII;
typedef pair<string,int>PSI;
typedef pair<string,string>PSS;
const int N=100+5,INF=0x3f3f3f3f,Mod=1e9+7,mod=998244353;
const int MAXN=1e8+5;
const double eps=1e-12;
const int dx[4]={-1,1,0,0};
const int dy[4]={0,0,-1,1};



void solve() {
    int n;
    cin>>n;
    vector<int>ve(n);
    for(int i=0;i<n;++i){
        cin>>ve[i];
    }
    sort(ve.begin(),ve.end());
    int mi=ve[0];
    int ans=(n-1)*2*mi,p=4*mi;
    for(int i=1;i<n;++i){
        if(2*ve[i]<p)ans+=2*ve[i]*(n-i-1);
        else ans+=p*(n-i-1);
    }
    cout<<ans*2<<'\n';
}

signed main(){
    ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
    int t=1;
    cin>>t;
    while(t--){
        solve();
    }
    return 0;
}
View Code

 

KTokitsukaze and Password (easy)

思路:n不大,暴力枚举

#include<bits/stdc++.h>
using namespace std;
#define int long long
//#define int __int128
#define double long double
typedef pair<int,int>PII;
typedef pair<string,int>PSI;
typedef pair<string,string>PSS;
const int N=1e5+5,INF=0x3f3f3f3f,Mod=1e9+7,mod=998244353;
const int MAXN=1e8+5;
const double eps=1e-12;
const int dx[4]={-1,1,0,0};
const int dy[4]={0,0,-1,1};


void solve() {
    int n,y;
    set<int>ans;
    string s;
    cin>>n>>s>>y;

    char a,b,c,d,e;
    for(a='0';a<='9';++a){
        for(b='0';b<='9';++b){
            for(c='0';c<='9';++c){
                for(d='0';d<='9';++d){
                    for(e='0';e<='9';++e){
                        if(a==b||b==c||c==d||a==d||a==c||b==d)continue;
                        string t=s;
                        for(int i=0;i<t.size();++i){
                            if(t[i]=='a')t[i]=a;
                            else if(t[i]=='b')t[i]=b;
                            else if(t[i]=='c')t[i]=c;
                            else if(t[i]=='d')t[i]=d;
                            else if(t[i]=='_')t[i]=e;
                        }
                        if(n>1&&t[0]=='0')continue;
                        int x=stoi(t);
                        if(x%8==0&&x<=y)ans.insert(x);
                    }
                }
            }
        }
    }
    cout<<ans.size()<<'\n';
}
signed main(){
    ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
    int t=1;
    cin>>t;
//    init();
    while(t--){
        solve();
    }
    return 0;
}
View Code

 

posted @ 2024-02-17 21:29  bible_w  阅读(11)  评论(0编辑  收藏  举报