2024杭电第三场

打了个爽!今天打得很稳,基本没有罚时,相当优雅的一场

1002 旅行

线段树合并经典题,顺便在过程中做个dp

#include<bits/stdc++.h>
using namespace std;
const int N = 2e5+5;
#define mid ((l+r)>>1)
typedef long long ll;
vector<int>e[N];
int tot,n,c[N],w[N],root[N];
ll nowsum,g[N];
struct seg_tree{
    int l,r;
    ll tag,sum;
}t[N<<6];
void up(int rt){
    int ls=t[rt].l,rs=t[rt].r;
    if(ls) t[rt].sum=max(t[rt].sum,t[ls].sum);
    if(rs) t[rt].sum=max(t[rt].sum,t[rs].sum);
}
void down(int rt){
    if(t[rt].tag==0) return;
    int ls=t[rt].l,rs=t[rt].r;
    if(ls)t[ls].tag+=t[rt].tag,t[ls].sum+=t[rt].tag;
    if(rs)t[rs].tag+=t[rt].tag,t[rs].sum+=t[rt].tag;
    t[rt].tag=0;
}
void add(int &rt,int l,int r,int x,int val){
    if(!rt) rt=++tot,t[rt].tag=t[rt].l=t[rt].r=t[rt].sum=0;
    if(l==r){
        t[rt].tag=0;
        t[rt].sum=val;
        return;
    }
    if(x<=mid) add(t[rt].l,l,mid,x,val);
    else add(t[rt].r,mid+1,r,x,val);
    up(rt);
}
int merge(int x,int y,int l,int r,ll &ans){
    if(!x || !y) return x+y;
    if(l==r){
        ans=max(ans,1ll*nowsum+t[x].sum+t[y].sum);
        t[x].sum=max(t[x].sum,t[y].sum);
        return x;
    }
    down(x),down(y);
    t[x].l=merge(t[x].l,t[y].l,l,mid,ans);
    t[x].r=merge(t[x].r,t[y].r,mid+1,r,ans);
    up(x);
    return x;
}
void dfs(int u,int fa){
    
//    cout<<u<<" "<<fa<<"\n";
    ll sum=0;
    for(auto v:e[u]){
        if(v==fa) continue;
        dfs(v,u);
        sum+=g[v];
    }
    g[u]=sum;
    nowsum=sum;
    add(root[u],1,n,c[u],w[u]);
    for(auto v:e[u]){
        if(v==fa) continue;
        
        t[root[v]].sum-=g[v];
        t[root[v]].tag-=g[v];
        root[u]=merge(root[u],root[v],1,n,g[u]);
    }
//    cout<<u<<" over "<<"\n";
    t[root[u]].tag+=sum;
    t[root[u]].sum+=sum;
}
void solve(){
    cin>>n;
    for(int i=1;i<=n;i++)
        cin>>c[i];
    for(int i=1;i<=n;i++)
        cin>>w[i];
    for(int i=1,u,v;i<n;i++){
        cin>>u>>v;e[u].push_back(v);e[v].push_back(u);
    }
    dfs(1,0);
    cout<<g[1]<<"\n";
    
    for(int i=1;i<=tot;i++)
        t[i]=(seg_tree){0,0,0,0};
    for(int i=1;i<=n;i++){
        root[i]=0;
        g[i]=0;
        e[i].clear();    
    }
    tot=0;
}   
int main(){
    //freopen("Test.in","r",stdin);
    ios_base::sync_with_stdio(false);
    cin.tie(0);cout.tie(0);
    int t;cin>>t;
    while(t--){
        solve();
    }
    return 0;
}

 

1001 

考虑递推,发现答案和因子有关,再加上森林里只有一棵树的情况 ( i个节点构成的树的种数为f[i-1] )

#include<bits/stdc++.h>
using namespace std;
const int N=1e6,mod=998244353;
inline int add(int x,int y){return (x+=y)>=mod?x-mod:x;}
int n,f[N+5],g[N+5];
void Kafka()
{
    cin>>n;
    f[0]=g[0]=1;
    for(int i=1;i<=n;++i)
    {
        g[i]=f[i-1];
        for(int j=1;i*j<=n;++j) f[i*j]=add(f[i*j],g[i]);
        cout<<f[i];
        if(i==n) cout<<endl;
        else cout<<' ';
    }
}
signed main()
{
    Kafka(); 
    return 0;
}

1012

题意转化为两个条件都不能满足,则

1. 实力>=L 的队伍只能有一支

2. 队内极差要超过D

分类讨论:

如果a1的实力>=L,那么只能找<L的,且为了构造极差,最好找最小值。判断个数够不够

如果a1的实力<L,那么为了构造极差,可以把最大值放进来,再把最小的放进来。同样判断个数够不够

实现的话自认为我的代码还是优雅的👉👈

有个小trick是单独把a1先拿出来

#include<bits/stdc++.h>
using namespace std;
const int N = 2e5+5;
int a[N];
void solve(){
    int n,l,d,a1;cin>>n>>l>>d;
    cin>>a1;
    n--;
    for(int i=1;i<=n;i++) cin>>a[i];
    sort(a+1,a+n+1);
    
    if(a1>=l){
        int cnt=0;
        for(int i=1;i<=n;i++){
            if(a[i]<l) cnt++;
        }
        if(cnt>=3&&a1-a[1]>d) {
            cout<<"Yes"<<"\n";
        }
        else cout<<"No"<<"\n";
    }
    else {
        int cnt=0;
        int tmp[5]={0};
        for(int i=1;i<=n-1;i++){
            if(a[i]<l){
                cnt++;tmp[cnt]=a[i];        
            }
            if(cnt==2) break;
        }
        if(cnt<2) {
            cout<<"No"<<"\n";
            return;
        }
        cnt++;tmp[cnt]=a1;
        cnt++;tmp[cnt]=a[n];
        sort(tmp+1,tmp+cnt+1);
        if(tmp[4]-tmp[1]>d) cout<<"Yes"<<"\n";
        else cout<<"No"<<"\n";
    }
}
int main(){
    ios_base::sync_with_stdio(false);
    cin.tie(0);cout.tie(0);
    int t;cin>>t;
    while(t--){
        //TODO
        solve();
    }
}

1007 单峰数列

区间加用差分

如果 [l,r] 是递增数列则 [l+1,r]的差分值应该都>0

如果 [l,r] 是递减数列则 [l+1,r]的差分值应该都<0

如果 [l,r] 是相等则 [l+1,r]的差分值应该都=0

线段树维护区间为0的个数、为正数的个数、为负数的个数即可

至于第5个询问,观察到 n<=1e5 ,可以先二分出递增序列的右端点ans,再检查 [ans+1,r]是否为递减数列,O(nloglog),能过

#include<bits/stdc++.h>
using namespace std;

inline int read()
{
    int x=0;bool f=1;char ch=getchar();
    for(;ch<'0'||ch>'9';ch=getchar())f^=(ch=='-');
    for(;ch>='0'&&ch<='9';ch=getchar())x=(x<<1)+(x<<3)+(ch^48);
    return f?x:-x;
}
const int N = 1e5+100;
#define ls (rt<<1)
#define rs (rt<<1|1)
#define mid ((l+r)>>1)
typedef long long ll;
ll a[N],c[N];
int n;
struct seg_tree{
    int zero,neg,posi;
}t[N<<2];
void up(int rt){
    t[rt].neg=t[ls].neg+t[rs].neg;
    t[rt].posi=t[ls].posi+t[rs].posi;
    t[rt].zero=t[ls].zero+t[rs].zero;
}
void uppoint(int rt,int l){
    t[rt].neg=t[rt].posi=t[rt].zero=0;
    if(c[l]==0)    t[rt].zero++;
    if(c[l]>0) t[rt].posi++;
    if(c[l]<0) t[rt].neg++;
}
void build(int rt=1,int l=1,int r=n){
    if(l==r){
        uppoint(rt,l);
        return;        
    }
    build(ls,l,mid);build(rs,mid+1,r);
    up(rt);
}
void update(int pos,int x,int rt=1,int l=1,int r=n){
    if(l==r){
        c[l]+=x;
        uppoint(rt,l);
        return;
    }
    if(pos<=mid) update(pos,x,ls,l,mid);
    if(pos>mid) update(pos,x,rs,mid+1,r);
    up(rt);
}
int q(int ql,int qr,int op,int rt=1,int l=1,int r=n){
    if(ql<=l&&r<=qr){
        if(op==0) return t[rt].zero;
        if(op==1) return t[rt].posi;
        if(op==-1) return t[rt].neg;
    }
    int ans=0;
    if(ql<=mid) ans+=q(ql,qr,op,ls,l,mid);
    if(qr>mid) ans+=q(ql,qr,op,rs,mid+1,r);
    return ans;
} 
void check(int x,int y){
    if(x==y) cout<<"1"<<"\n";
    else cout<<"0"<<"\n";
}
signed main(){    
    n=read();
    for(int i=1;i<=n;i++)  a[i]=read();
    for(int i=1;i<=n;i++)  c[i]=a[i]-a[i-1];
    build(1,1,n);
    int Q=read();
    while(Q--){
        int op;op=read();
        if(op==1){
            int l,r,x;
            l=read(),r=read(),x=read();
            update(l,x);update(r+1,-x);
        }
        if(op==2){
            int l,r;l=read(),r=read();
            if(l==r) {
                cout<<1<<"\n";
                continue;
            }
            int num=q(l+1,r,0);
            check(num,r-l);
        }
        if(op==3){
            int l,r;l=read(),r=read();
            if(l==r) {
                cout<<1<<"\n";
                continue;
            }
            int num=q(l+1,r,1);
            check(num,r-l);
        }
        if(op==4){
            int l,r;l=read(),r=read();
            if(l==r) {
                cout<<1<<"\n";
                continue;
            }
            int num=q(l+1,r,-1);
            check(num,r-l);
        }
        if(op==5){
            int l,r;l=read(),r=read();
            int L=l+1,R=r,ans=-1;
            while(L<=R){
                int Mid=(L+R)>>1;
                int len=Mid-l;
                if(q(l+1,Mid,1)==len){
                    ans=Mid;
                    L=Mid+1;
                }
                else R=Mid-1;
            }
            if(ans==-1) {
                cout<<"0"<<"\n";
                continue;    
            }
            if(q(l+1,r,1)==r-l) {
                cout<<0<<"\n";
                continue;
            }
            if(q(ans+1,r,-1)==r-(ans+1)+1){
                cout<<1<<"\n";
            }
            else cout<<0<<"\n";
        }
    }
    return 0;
}

1011

队友写的

#include<bits/stdc++.h>
#define int long long
#define u i
#define r (i+1)%4
#define d (i+2)%4
#define l (i+3)%4
using namespace std;
struct node{
    int x,y;
}a[4][4];

inline int read()
{
    int x=0;bool f=1;char ch=getchar();
    for(;ch<'0'||ch>'9';ch=getchar())f^=(ch=='-');
    for(;ch>='0'&&ch<='9';ch=getchar())x=(x<<1)+(x<<3)+(ch^48);
    return f?x:-x;
}
int fx(char c){
    if (c=='N') return 0;
    if (c=='E') return 1;
    if (c=='S') return 2;
    if (c=='W') return 3;
    
}
const int N=505;
const int INF=1e9+505;
const int dx[]={0,1,0,-1};
const int dy[]={1,0,-1,0};
const node Null={INF,INF};
int n;
int tim[N],wall[4],num;
bool isNull(node a){
    return a.x==INF&&a.y==INF;
}
node mx(node a,node b,int k){
    if (isNull(b)) return a;
    if (isNull(a)) return b;
    if (k==0) return a.y>b.y?a:b;
    if (k==1) return a.x>b.x?a:b;
    if (k==2) return a.y<b.y?a:b;
    if (k==3) return a.x<b.x?a:b;
}
int sol(node a,node b,int k){
    if (isNull(a)) return -1;
    if (isNull(b)) return -1;
    if (k==0) return a.y-b.y;
    if (k==1) return a.x-b.x;
    if (k==2) return b.y-a.y;
    if (k==3) return b.x-a.x;
}
void test(){
    return;
    for (int i=0;i<4;i++){
        for (int j=0;j<4;j++)
            printf("a[%lld][%lld]=%lld %lld\n",i,j,a[i][j].x,a[i][j].y);
        printf("\n");    
    }

}
void add(int x,int y,int k){
    for (int i=0;i<4;i++)
        a[i][k]=mx(a[i][k],{x,y},i);
    //test();
}
void addtime(int x){
    if (x<0) return;
    tim[++num]=x;
}
node go(node a,int k,int t){
    if (a.x==INF&&a.y==INF) return Null;
    a.x+=dx[k]*t;
    a.y+=dy[k]*t;
    return a;
}
void pt(node a){
    //printf("%lld %lld ",a.x,a.y);
}
int cal(int t){
    node tmp[4];
    for (int i=0;i<4;i++)
        tmp[i]=Null;
    for (int i=0;i<4;i++){
        for (int j=0;j<4;j++){
            tmp[i]=mx(tmp[i],go(a[i][j],j,t),i);
            //printf("tmp[%lld]=%lld %lld\n",i,tmp[i].x,tmp[i].y);
            //test();
            /*
            if (t==1){
                printf("i=%lld j=%lld ",i,j);
                pt(a[i][j]);
                pt(go(a[i][j],j,t));
                printf("\n");
            }
            */            
        }

                
    }
    int y=tmp[0].y-tmp[2].y;
    int x=tmp[1].x-tmp[3].x;
    //printf("t=%lld xi=%lld xa=%lld yi=%lld ya=%lld\n",t,tmp[3].x,tmp[1].x,tmp[2].y,tmp[0].y);
    return 2*(x+y);
}
void work(){
    node tmp;
    for (int i=0;i<4;i++){
        tmp=mx(a[i][l],a[i][r],i);
        if (isNull(tmp)) {
            int x=sol(a[i][u],a[i][d],d);
            //pt(a[i][u]);
            //pt(a[i][d]);            
            //printf("i=%lld x=%lld\n",i,x);
            //test();
            if (x==-1) continue;
            addtime(x/2);
            addtime((x+1)/2);
            continue;
        }
        addtime(sol(tmp,a[i][u],u));
        addtime(sol(tmp,a[i][d],d));

    }
    int res=cal(0);
    //cerr << "case1:" << res << endl;
    //cerr << "case2:" << num << endl;
    //cerr << "case3:" << tim[1] << endl;
    for (int i=1;i<=num;i++)
        res=min(res,cal(tim[i]));
    cout << res << endl;
}
signed main()
{
    for (int i=0;i<4;i++)
        for (int j=0;j<4;j++)
            a[i][j]=Null;
    cin >> n;
    for (int i=1;i<=n;i++){
        int x,y; char c;
        cin >> x >> y >> c;
        add(x,y,fx(c));
    }
    work();
    return 0;
}

1008 

首先证明了跳跃时一定是从x跳到x的超集,否则不如直接从1跳到x

那么对于当前dij扩展到的节点j,枚举它的超集,设x为j的超集中的某个元素,假设 x 没有被访问过,则从 j 跳到 x 一定是最优解

因为k*(x|y)这部分代价一样,但是最短路的部分当前是最优解(dij的特性,最早扩展完的点dis值越小)

实现是扩展的时候dfs搜一下

#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=1e5,LIM=20;
int n,m,k,dis[N+5];
vector<pair<int,int> > ver[N+5];
priority_queue<pair<int,int> > q;
bool vis[N+5],jm[N+5];
inline int read()
{
    int x=0;bool f=1;char ch=getchar();
    for(;ch<'0'||ch>'9';ch=getchar())f^=(ch=='-');
    for(;ch>='0'&&ch<='9';ch=getchar())x=(x<<1)+(x<<3)+(ch^48);
    return f?x:-x;
}
int jump(int x,int y){return k*(x|y);}
void dfs(int x,int r)
{
    for(int i=0,v,y;i<LIM;++i)
    {
        if(x&(1<<i)) continue;
        y=x^(1<<i);
        if(jm[y]||y>n) continue;
        v=k*y,jm[y]=1;
        if(dis[y]==-1||dis[y]>dis[r]+v) dis[y]=dis[r]+v,q.push(make_pair(-dis[y],y));
        dfs(y,r);
    }
}
void dijkstra()
{
    for(int i=1;i<=n;++i) dis[i]=-1;
    for(int i=1;i<=n;++i) vis[i]=0;
    for(int i=1;i<=n;++i) jm[i]=0;
    dis[1]=0,q.push(make_pair(0,1));
    for(int x;q.size();)
    {
        x=q.top().second,q.pop();
        if(vis[x]) continue;
        vis[x]=1;
        for(int i=0,lim=ver[x].size();i<lim;++i)
        {
            int y=ver[x][i].second,v=ver[x][i].first;
            if(dis[y]==-1||dis[y]>dis[x]+v) dis[y]=dis[x]+v,q.push(make_pair(-dis[y],y));
        }
        dfs(x,x);
    }
}
void Kafka()
{
    n=read(),m=read(),k=read();
    for(int i=1;i<=n;++i) ver[i].clear();
    for(int i=1;i<=m;++i)
    {
        int u=read(),v=read(),w=read();
        if(w>jump(u,v)) w=jump(u,v);
        ver[u].push_back(make_pair(w,v));
        ver[v].push_back(make_pair(w,u));
    }
    for(int i=2;i<=n;++i) ver[1].push_back(make_pair(jump(1,i),i)),ver[i].push_back(make_pair(jump(1,i),1));
    dijkstra();
    for(int i=2;i<=n;++i) cout<<dis[i]<<(i==n?'\n':' ');
}
signed main()
{
    for(int T=read();T--;) Kafka();
    return 0;
}

 

posted @ 2024-07-26 19:50  liyishui  阅读(161)  评论(0编辑  收藏  举报