2023河南萌新联赛第(一)场:河南农业大学 11/12

晚来了一小时,终榜14名,血亏

https://ac.nowcoder.com/acm/contest/61132

A题不会,我选择oeis

n=int(input())
print(n*(n+1)*(n+2)//6%1000000007)
python代码

B题考虑线段树f[x][i][0]表示如果x所统辖的区间里,x第i位为0做计算得到的值,f[x][i][1]表示x所统辖的区间里,第i位为1做计算得到的值

那么叶子节点可以写三个if,合并两个区间时可以使用

        f[x][i][0]=f[x*2+1][i][f[x*2][i][0]!=0];
        f[x][i][1]=f[x*2+1][i][f[x*2][i][1]!=0];
询问时可以把[l,r]区间的转移矩阵合并,最后对于x的每一位计算答案
合并操作;
        for(int i=0;i<=20;i++)
        {
            t[i][0]=f[x][i][t[i][0]!=0];
            t[i][1]=f[x][i][t[i][1]!=0];
        }
计算答案:
            for(int i=0;i<=20;i++)
            {
                ans=ans+t[i][ (x&(1<<i))!=0] ;
            }
(太C了,写了十五分钟就过了)
#include<bits/stdc++.h> 
using namespace std;
typedef long long ll;
ll read()
{
    ll x;scanf("%lld",&x);return x;
}
int n;
char s[100010];
int f[400010][25][2],t[25][2],a[100010];
int work(int xx,char c,int yy)
{
    if(c=='|')
        return xx|yy;
    else if(c=='^')
        return xx^yy;
    else
        return xx&yy;
}
void build(int x,int l,int r)
{
    if(l==r)
    {

        for(int i=0;i<=20;i++)
        {
            f[x][i][0]=work(0,s[l],a[l]&(1<<i));
            f[x][i][1]=work(1<<i,s[l],a[l]&(1<<i));
        }
        return ;
    }
    int mid=(l+r)/2;
    build(x*2,l,mid);
    build(x*2+1,mid+1,r);
    for(int i=0;i<=20;i++)
    {
        f[x][i][0]=f[x*2+1][i][f[x*2][i][0]!=0];
        f[x][i][1]=f[x*2+1][i][f[x*2][i][1]!=0];
    }
}
void add(int x,int l,int r,int d)
{
    if(l==r)
    {
        for(int i=0;i<=20;i++)
        {
            f[x][i][0]=work(0,s[l],a[l]&(1<<i));
            f[x][i][1]=work(1<<i,s[l],a[l]&(1<<i));
        }
        return ;
    }
    int mid=(l+r)/2;
    if(d<=mid)
        add(x*2,l,mid,d);
    else
        add(x*2+1,mid+1,r,d);
    for(int i=0;i<=20;i++)
    {
        f[x][i][0]=f[x*2+1][i][f[x*2][i][0]!=0];
        f[x][i][1]=f[x*2+1][i][f[x*2][i][1]!=0];
    }
}
void ask(int x,int l,int r,int tl,int tr )
{
    if(tl<=l&&r<=tr)
    {
        for(int i=0;i<=20;i++)
        {
            t[i][0]=f[x][i][t[i][0]!=0];
            t[i][1]=f[x][i][t[i][1]!=0];
        }
        return ;
    }
    int mid=(l+r)/2;
    if(tl<=mid)
        ask(x*2,l,mid,tl,tr);
    if(tr>mid)
        ask(x*2+1,mid+1,r,tl,tr);
}
int main()
{
//     freopen("1.in","r",stdin);
    n=read();
    scanf("%s",s+1);
    for(int i=1;i<=n;i++)
        a[i]=read();
    build(1,1,n);
    for(int m=read();m;m--)
    {
        if(read()&1)
        {
            int pos=read();
            a[pos]=read();
            add(1,1,n,pos);
        }
        else
        {
            int x=read(),l=read(),r=read(),ans=0;
            for(int i=0;i<=20;i++)
            {
                t[i][0]=0;
                t[i][1]=(1<<i);
            }
            ask(1,1,n,l,r);
            for(int i=0;i<=20;i++)
            {
                ans=ans+t[i][ (x&(1<<i))!=0] ;
            }
            printf("%d\n",ans);
        }
    }
}
B

 C 

如果先手一次能赢,输出alice

如果先手第一次怎么动,后手第一次一定能赢,输出Bob

否则输出平局

D

考虑二分答案,问题转变成判断,只经过小于等于val的点,到达ed的最短路是否小于等于h,暴力跑一跑即可。

#include<bits/stdc++.h> 
using namespace std;
typedef long long ll;
ll read()
{
    ll x;scanf("%lld",&x);return x;
}
int n,m,st,ed,a[10010],vis[10010],h;
ll d[10010];
queue<int>q;
vector<int>e[10010],v[10010];
int check(int val)//要求路上的松果数量<=val
{
    memset(d,0x3f,sizeof(d));
    if(a[st]>val)
        return 0;
    d[st]=0;
    q.push(st);
    while(q.size())
    {
        int tx=q.front();
        q.pop();
        vis[tx]=0;
        for(int i=0;i<e[tx].size();i++)
        {
            if(a[e[tx][i]]<=val&&d[tx]+v[tx][i]<d[e[tx][i]])
            {
                d[e[tx][i]]=d[tx]+v[tx][i];
                if(vis[e[tx][i]]==0)
                {
                    vis[e[tx][i]]=1;
                    q.push(e[tx][i]);
                }
            }
        }
    }
    if(d[ed]<=h)
        return 1;
    return 0;
}
int main()
{
    // freopen("1.in","r",stdin);
    n=read();m=read();st=read();ed=read();h=read();
    for(int i=1;i<=n;i++)
        a[i]=read();
    for(int i=1;i<=m;i++)
    {
        int x=read(),y=read(),z=read();
        e[x].push_back(y);
        v[x].push_back(z);
        e[y].push_back(x);
        v[y].push_back(z);
    }
    int l=1,r=10000000,mid;
    while(l+1<r)
    {
        mid=(l+r)/2;
        if(check(mid))
            r=mid;
        else
            l=mid;
    }
    if(check(l))
        cout<<l;
    else if(check(r))
        cout<<r;
    else
        cout<<-1;
}
D

 E

对于当前前缀和sum,只需判断sum-m是否出现过即可,用前缀和维护一下。

#include<bits/stdc++.h> 
using namespace std;
typedef long long ll;
ll read()
{
    ll x;scanf("%lld",&x);return x;
}
int n,m,ans;
ll sum;
map<ll,int>o;
int main()
{
    n=read();m=read();
    o[0]=1;
    for(int i=1;i<=n;i++)
    {
        sum=sum+read();
        ans=ans+o[sum-m];
        o[sum]++;
    }
    cout<<ans;
}
E

F

#include<bits/stdc++.h> 
using namespace std;
typedef long long ll;
ll read()
{
    ll x;scanf("%lld",&x);return x;
}
int ans;
int n,a[100010],fa[100010];
int get(int x)
{
    return fa[x]==x?x:fa[x]=get(fa[x]);
}
void merge(int x,int y)
{
    if(get(x)==get(y))
        return ;
    fa[get(x)]=get(y);
}
int main()
{
    n=read();
    for(int i=1;i<=n;i++)
        fa[i]=i;
    for(int i=1;i<=n;i++)
    {

        a[i]=read();
        merge(a[i],i);
    }
    ans=n;
    for(int i=1;i<=n;i++)
        if(i==get(i))
            ans--;
    cout<<ans;
}
F

 G

如果原来的串没有连续为1的段,那么当然输出0
只有一个连续为1的段,那就输出这个串的长度
否则,如果有多个连续为1的串,可以把最长的两串转到一块,这样一定是最大的
#include<bits/stdc++.h> 
using namespace std;
typedef long long ll;
ll read()
{
    ll x;scanf("%lld",&x);return x;
}
int n,sum;
char s[1000010];
vector<int>a;
int main()
{
    n=read();
    scanf("%s",s+1);
    for(int i=1;i<=n;i++)
    {
        if(s[i]=='1')
            sum++;
        else
        {
            a.push_back(sum);
            sum=0;
        }
    }
    if(sum)
        a.push_back(sum);
    sort(a.begin(),a.end());
    if(a.size()==0)
        cout<<0;
    if(a.size()==1)
        printf("%d",a[0]);
    else
        printf("%d",a[a.size()-1]+a[a.size()-2]);
}
G

H

01bfs板子题
#include<bits/stdc++.h> 
using namespace std;
typedef long long ll;
ll read()
{
    ll x;scanf("%lld",&x);return x;
}
int n,m,d[3010][3010],len[3010][3010];
char s[3010][3010];
int dx[]={0,0,1,-1},dy[]={1,-1,0,0};
deque<pair<int,int>>q;
int main()
{
    n=read();m=read();
    for(int i=1;i<=n;i++)
        scanf("%s",s[i]+1);
    for(int i=read();i;i--)
    {
        int x=read(),y=read();
        len[x][y]=read();
    }
    memset(d,0x3f,sizeof(d));
    d[1][1]=0;
    q.push_front({1,1});
    while(q.size())
    {
        int x=q.front().first,y=q.front().second;
        int tx,ty;
        q.pop_front();
        if(s[x][y]=='.')
            for(int i=0;i<4;i++)
            {
                tx=x+dx[i];
                ty=y+dy[i];
                if(tx&&ty&&tx<=n&&ty<=m&&s[tx][ty]!='#'&&d[tx][ty]>d[x][y]+1)
                {
                    d[tx][ty]=d[x][y]+1;
                    q.push_back({tx,ty});
                }

            }
        else
            for(int i=0;i<4;i++)
            {
                tx=x+dx[i]*len[x][y];
                ty=y+dy[i]*len[x][y];
                if(tx>=1&&ty>=1&&tx<=n&&ty<=m&&s[tx][ty]!='#'&&d[tx][ty]>d[x][y])
                {
                    d[tx][ty]=d[x][y];
                    q.push_front({tx,ty});
                }

            }

    }
    if(d[n][m]==0x3f3f3f3f)
        d[n][m]=-1;
    cout<<d[n][m];
}
H

I

lca+树上差分,wa了半天,17分钟过样例交了,一小时后才过,自闭极了
考虑在x点到y点的简单路径上所有的边都增加add个松果
这个操作,是链上加,可以对x加add,对y+add,对lca(x,y)减2倍的add
然后从差分数组整一下原数组
每次询问lca一下即可。
#include<bits/stdc++.h> 
using namespace std;
typedef long long ll;
ll read()
{
    ll x;scanf("%lld",&x);return x;
}
int n,m,q,fa[100010][25],deep[100010];
ll d[100010][25],v[100010];
vector<pair<int,ll>>e[100010];
void dfs(int x)
{
    for(auto y:e[x])
    {
        if(y.first==fa[x][0])continue;
        deep[y.first]=deep[x]+1;
        fa[y.first][0]=x;
        dfs(y.first);
    }
}
int lca(int x,int y)
{
    if(deep[x]>deep[y])swap(x,y);
    for(int i=20;i>=0;i--)
        if(deep[fa[y][i]]>=deep[x])
            y=fa[y][i];
    if(x==y)
        return x;
    for(int i=20;i>=0;i--)
        if(fa[x][i]!=fa[y][i])
            x=fa[x][i],y=fa[y][i];
    return fa[x][0];
}
ll ask(int x,int y)
{
    ll t=0;
    if(deep[x]>deep[y])swap(x,y);
    for(int i=20;i>=0;i--)
        if(deep[fa[y][i]]>=deep[x])
        {
            t=t+d[y][i];
            y=fa[y][i];
        }
    if(x==y)
        return t;
    for(int i=20;i>=0;i--)
        if(fa[x][i]!=fa[y][i]){
            t=t+d[x][i];
            t=t+d[y][i];
            x=fa[x][i],y=fa[y][i];
        }
    return t+d[x][0]+d[y][0];
}
ll dfs0(int x)
{
    ll sum=v[x];
    for(auto y:e[x])
    {
        if(y.first==fa[x][0])continue;
        ll t=dfs0(y.first);
        sum+=t;
        d[y.first][0]=y.second+t;
    }
    return sum;
}
int main()
{
    // freopen("1.in","r",stdin);
    n=read();m=read();q=read();
    for(int i=1;i<n;i++)
    {
        int x=read(),y=read(),v=read();
        e[x].push_back({y,v});
        e[y].push_back({x,v});
    }
    deep[1]=1;
    dfs(1);

    for(int i=1;i<=20;i++)
        for(int x=1;x<=n;x++)
            fa[x][i]=fa[fa[x][i-1]][i-1];
    for(int i=1;i<=m;i++)
    {
        int x=read(),y=read(),tv=read();
        v[x]+=tv;
        v[y]+=tv;
        v[lca(x,y)]-=2*tv;
    }
    dfs0(1);
    for(int i=1;i<=20;i++)
        for(int x=1;x<=n;x++)
            d[x][i]=d[x][i-1]+d[fa[x][i-1]][i-1];
    for(int i=1;i<=q;i++)
    {
        int x=read(),y=read();
        printf("%lld\n",ask(x,y));
    }
}
I

J

简单签到题
#include<bits/stdc++.h> 
using namespace std;
typedef long long ll;
ll read()
{
    ll x;scanf("%lld",&x);return x;
}
int a[1010],n,sum;
int main()
{
    n=read();
    for(int i=1;i<=n;i++)
        a[i]=read();
    a[0]=1;

    sort(a+0,a+1+n);
    for(int i=1;i<n;i++)
        sum=sum+a[i];
    printf("%.6lf ",sum*1.0/(n-1));
    a[0]=100;sum=0;
    sort(a+0,a+1+n);
    for(int i=1;i<n;i++)
        sum=sum+a[i];
    printf("%.6lf",sum*1.0/(n-1));
}
J

K

模拟,对于每个房间,判断一下上下左右
#include<bits/stdc++.h> 
using namespace std;
typedef long long ll;
ll read()
{
    ll x;scanf("%lld",&x);return x;
}
int n,m,ans;
char s[1010][1010];
int main()
{
    n=read();m=read();
    for(int i=1;i<=n;i++)
        scanf("%s",s[i]+1);
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=m;j++)
        {
            if(s[i][j]!='0')continue;
            int sum=0;
            if(s[i][j+1]=='2'||s[i][j-1]=='2'||s[i+1][j]=='2'||s[i-1][j]=='2')
                continue;
            sum=sum+(s[i][j+1]=='1');
            sum=sum+(s[i][j-1]=='1');
            sum=sum+(s[i-1][j]=='1');
            sum=sum+(s[i+1][j]=='1');
            if(sum==3)
                ans++;
        }
    }
    if(ans)
        cout<<"YES"<<endl<<ans;
    else
        cout<<"NO";
}
K

L

考虑用值域线段树维护当前的数组,查询中位数可以使用线段树上二分
#include<bits/stdc++.h> 
using namespace std;
typedef long long ll;
ll read()
{
    ll x;scanf("%lld",&x);return x;
}
int c[4000010],n,a[1000010],m;
void add(int x,int l,int r,int d,int v)
{
    c[x]+=v;
    if(l==r)
        return ;
    int mid=(l+r)/2;
    if(d<=mid)
        add(x*2,l,mid,d,v);
    else
        add(x*2+1,mid+1,r,d,v);
}
int ask(int x,int l,int r,int sum)
{
    // cout<<x<<" "<<l<<' '<<r<<' '<<c[x]<<" "<<sum<<endl;
    if(l==r)
        return l;
    int mid=(l+r)/2;
    if(c[x*2]>=sum)
        return ask(x*2,l,mid,sum);
    else
        return ask(x*2+1,mid+1,r,sum-c[x*2]);
}
int main()
{
    n=read();m=read();
    for(int i=1;i<=n;i++)
    {
        a[i]=read();
        add(1,1,1000000,a[i],1);
    }
    n=n/2+1;
    for(int i=1;i<=m;i++)
    {
        int p=read(),x=read();
        add(1,1,1000000,a[p],-1);
        a[p]=x;
        add(1,1,1000000,x,1);
        printf("%d\n",ask(1,1,1000000,n));
    }
}
L

 

posted @ 2023-07-12 17:23  zzuqy  阅读(172)  评论(1编辑  收藏  举报