2022HDU多校第四场

2022HDU多校第四场

过程

三题签到完成,吉吉在看了11一会后将01秒了,这里是我dp不够熟练,只能让吉吉来了,我好菜呀(哭),然后就坐牢开始了,我们轮流卡02和11,最后4题结束,惨淡收场。02属于是没想明白,另外时间不够,而11属实是坐大牢,看着它被人过穿,我们却毫无头绪,再一次在签到题上卡了太多时间,属实输麻了。赛后经人点拨,发现\(xor(l,r)\)如果\(l=r\)那么会变成0,那么题意就变成了求数组内异同或最大值,成了线性基板题,我哭死,再一次演了队友,下次不敢也不能在演了,队友要把我吃了。

题解

04

输出No即可

06

阅读理解题,理解题意后即可过,但这里我没想到\(1e6\)\(cin\)读入\(double\)类型\(tle\)了,改成\(scanf\)就过了

07

因为所有的怪都要打过,假设当前位置为\(l\),那么每次一定是跳到一个位置\(r\),按照从\(r\)\(l\)的方式依次将所有怪打过,再从\(r+1\)开始,因此我们设置一个当前所需能打过区间内所有怪的值,\(tmp=max(tmp-a[i],a[i])\),当我们的能力值大于这一值时,便可将这一区间所有怪打过,获得它们的生命值,当这个区间长度大于k时或者打不完怪时,输出\("NO"\)

void solve(){
    cin>>n>>a[0]>>k;
    ll sum=a[0];
    int dis=0,pos;
    bool flag=1;
    ll tmp=0,tep=0;
    rep(i,1,n){
        a[i]=read();
        if(!tmp) tmp=a[i],pos=i;
        else tmp=max(tmp-a[i],a[i]);
        //想要将整个区间怪打过所需最小的战力
        dis++;
        tep+=a[i];//区间累计可获得战力和
        if(dis>k) flag=0;
        if(sum>=tmp) {tmp=0;sum+=tep;tep=0;dis=0;}
    }
    if(dis) flag=0;
    if(flag) puts("YES");
    else puts("NO");
}

11

注意到可以把一些位置变为0,那么可以等价为n个数中的异或最大值,套用线性基。
关于线性基此处应该再强化认识一下。

int n;
ll d[60];
void insert(ll x){
    rpe(i,50,0){
        if(x&(1LL<<i)){
            if(d[i]) x^=d[i];
            else {
                d[i]=x;break;
            }
        }
    }
}
void solve(){
    cin>>n;
    rep(i,0,50) d[i]=0;
    rep(i,1,n){
        ll tmp;scanf("%lld",&tmp);
        insert(tmp);
    }    
    ll ans=0;
    rpe(i,50,0){
        if((ans^d[i])>ans) ans^=d[i];
    }
    printf("%lld\n",ans);
}

01

一眼区间DP,但我DP实在是做少了,属于是弱项了。
首先\(n\)必须是偶数,\(n\)为奇数直接输出\(0\)
\(dp[i][j]\)表示区间\([i,j]\)内可行的匹配数,首先枚举区间长度,然后枚举起点,得到终点,然后枚举区间断点,此时转移方程\(dp[i][j]=dp[i+1][mid-1]*dp[mid+1][j]*check(i,j)的求和\),即区间\([i+1,mid-1]\)和区间\([mid+1,j]\)可行的匹配个数与\((i,mid)\)是否能匹配的乘积,这里判断\((i,j)\)是否能匹配是个需要注意的点,一定是正数在前,负数在后。

int n,m;
ll dp[maxn][maxn];
int a[maxn];
int gett(int i,int j){//i和j搭配的方法数
    if(i+j==0) {
        if(i==j) return m;
        else if(i>0) return 1;
        else return 0;
    }
    else{
        if(i==0&&j<0) return 1;
        else if(i>0&&j==0) return 1;
        return 0; 
    }
}
void solve(){
    cin>>n>>m;
    rep(i,1,n) scanf("%d",&a[i]);
    if(n&1) {puts("0");return;}
    rep(i,1,n) rep(j,1,n) dp[i][j]=0;
    for(int len=2;len<=n;len+=2){
        rep(i,1,n){
            int j=i+len-1;
            if(j>n) break;
            for(int mid=i+1;mid<=j;mid+=2){
                ll z,b,c;
                if(mid>i+1) z=dp[i+1][mid-1];
                else z=1;
                if(mid<j) b=dp[mid+1][j];
                else b=1;
                c=gett(a[i],a[mid]);
                dp[i][j]=(dp[i][j] + z*b%mod*c%mod)%mod;
            }
        }
    }
    printf("%lld\n",dp[1][n]%mod);
}

02

本题直接跑dijkstra是错误的,因为存在0环,即路程和奖励都为0,因此正确步骤为建立出最短路图,在最短路图中进行缩点去除0环,然后跑最长路得到最大奖励,这里直接记忆化搜索。

struct Dijkstra{
    bool vis[maxn];
    ll dis[maxn];
    struct node{
        ll dis;int id;
        bool operator < (const node &a)const{
            return dis>a.dis;
        }
    };
    priority_queue<node>q;
    vector<P>G[maxn];
    void add(int u,int v,int w){
        G[u].pb({v,w});
    }
    inline void clear(int n){rep(i,1,n) G[i].clear();}
    void Dijk(int st,int n){
        while(!q.empty()) q.pop();
        rep(i,1,n) vis[i]=0,dis[i]=linf;
        dis[st]=0;
        q.push((node){0,st});
        while(!q.empty()){
            int u=q.top().id;q.pop();
            if(vis[u]) continue;
            vis[u]=1;
            for(auto x:G[u]){
                int w=x.second,v=x.first;
                if(dis[v]>dis[u]+w){
                    dis[v]=dis[u]+w;
                    q.push((node){dis[v],v});
                } 
            }
        }
    }
}D1,D2;

struct Tarjan{
    int dfn[maxn],low[maxn],timee=0;
    int scc_cnt=0,top=0,stck[maxn];
    bool vis[maxn];
    int bl[maxn];
    vector<int>G[maxn];
    void add(int u,int v){G[u].pb(v);}
    void clear(int n){
        timee=scc_cnt=top=0;
        rep(i,1,n) {
            vis[i]=dfn[i]=low[i]=0;
            G[i].clear();
        }
    }
    void tarjan(int now){
        dfn[now]=low[now]=++timee;
        stck[++top]=now;vis[now]=1;
        for(auto v:G[now]){
            if(!dfn[v]) tarjan(v),low[now]=min(low[now],low[v]);
            else if(vis[v]) low[now]=min(low[now],dfn[v]);
        }
        if(dfn[now]==low[now]){
            scc_cnt++;int tmp;
            do{
                tmp=stck[top--];
                vis[tmp]=0;
                bl[tmp]=scc_cnt;
            }while(now!=tmp);
        }
    }
}tar;

int n,m;
struct edge{int u,v,w,f;}Edge[maxm];
vector<P>G[maxn];
ll dp[maxn];
ll dfs(int now){
    if(dp[now]) return dp[now];
    for(auto v:G[now]){
        dp[now]=max(dp[now],dfs(v.first)+v.second);
    }
    return dp[now];
}
void solve(){
    cin>>n>>m;
    rep(i,1,m){
        int u,v,w,f;
        scanf("%d %d %d %d",&u,&v,&w,&f);
        Edge[i]=(edge){u,v,w,f};
        D1.add(u,v,w);D2.add(v,u,w);
    }
    D1.Dijk(1,n);D2.Dijk(n,n);
    ll dis=D1.dis[n];
    int cnt=0;
    rep(i,1,m){//得到最短路图
        int u=Edge[i].u,v=Edge[i].v,w=Edge[i].w;
        if(D1.dis[u]+w+D2.dis[v]==dis){
            Edge[++cnt]=Edge[i];
            tar.add(Edge[i].u,Edge[i].v);
        }
    }
    rep(i,1,n) if(!tar.dfn[i]) tar.tarjan(i);
    rep(i,1,cnt){
        int u=Edge[i].u,v=Edge[i].v;
        if(tar.bl[u]!=tar.bl[v]){
            G[tar.bl[u]].pb(P(tar.bl[v],Edge[i].f));
        }
    }
    ll ans=0;
    rep(i,1,tar.scc_cnt){
        if(!dp[i]) dfs(i);
        ans=max(ans,dp[i]);
    }
    rep(i,1,tar.scc_cnt) dp[i]=0;
    printf("%lld %lld\n",dis,ans);
    //clear
    D1.clear(n);D2.clear(n);tar.clear(n);
    rep(i,1,n) G[i].clear();
}

03

05

posted @ 2022-07-29 21:52  Mr_cold  阅读(25)  评论(0编辑  收藏  举报