zoukankan      html  css  js  c++  java
  • 2019 杭电多校第一场 题解


     

    总结:

    数据范围问题(int / long long )

    题意问题

    try a try. 1e4dinic冲冲冲

    不要看到过的人暂时比较少就不敢写,@byf

    比赛不要划水聊天

     


    题解:

    A Blank

     题意:题目意思是让你去找一个有n个数的数组,这个数组里面的数只有{0,1,2,3}。然后给你m个条件,每个条件有一组l,r,x,表示在数组l,r区间的有x个不同的数。

    问你这样的数组有多少个。

    思路:比赛时没想到,,,看题解写的。定义 dp[i][j][k][t] 代表填完前 t 个位置后,{0, 1, 2, 3} 这 4 个数字最后一次出现的位置,排序后为 i, j, k, t(i < j < k < t) 的方案数目,则按照第 t + 1 位的数字的四种选择,可以得到四种转移。对于限制可以按照限制区间的右端点分类,求出 dp[i][j][k][t] 后,找到所有以 t 为区间右端点的限制条件,如果当前状态不满足所有限制条件则不合法,不再向后转移。

     

    参考代码:

    #include<bits/stdc++.h>
    using namespace std;
    #define pii pair<in,int>
    #define mkp make_pair
    #define fi first
    #define se second
    #define pb push_back
    #define mod 998244353
    typedef long long ll;
    inline int read()
    {
        int x=0,f=1;char ch=getchar();
        while(ch<'0'||ch>'9'){if(ch=='-') f=-1; ch=getchar();}
        while(ch>='0'&&ch<='9'){x=(x<<3)+(x<<1)+ch-'0';ch=getchar();}
        return x*f;
    }
    void add(int &a,int b){a+=b;if(a>=mod)a-=mod;} 
    const int maxn=110;
    int T,n,m,ans;
    int f[maxn][maxn][maxn][2];
    vector<pair<int,int> > d[maxn];
    
    int main()
    {
        T=read();
        while(T--)
        {
            int l,r,x;
            ans=0;
            n=read();m=read();
            for(int i=1;i<=n;i++)
            {
                d[i].clear();
                  d[i].pb(mkp(i,1));
            }   
            for(int i=1;i<=m;i++)
            {
                   l=read(),r=read(),x=read();
                   d[r].pb(mkp(l,x));
            }
            memset(f,0,sizeof(f));
            f[0][0][0][0]=1;
            for(int cur=1;cur<=n;++cur)
            {
                int o=cur&1;
                for(int i=0;i<=cur;++i)
                    for(int j=i;j<=cur;++j)
                        for(int k=j;k<=cur;++k)
                            f[i][j][k][o]=0;
                            
                for(int i=0;i<=cur;++i)
                    for(int j=i;j<=cur;++j)
                        for(int k=j;k<=cur;++k)
                        {
                            add(f[j][k][cur-1][o],f[i][j][k][o^1]);
                            add(f[i][k][cur-1][o],f[i][j][k][o^1]);    
                            add(f[i][j][cur-1][o],f[i][j][k][o^1]);
                            add(f[i][j][k][o],f[i][j][k][o^1]);
                        }
                        
                for(int i=0;i<=cur;++i)
                    for(int j=i;j<=cur;++j)
                        for(int k=j;k<=cur;++k)
                        {    
                            for(auto pi:d[cur])
                               {
                                   int l=pi.first,r=cur,x=pi.second;
                                   if((i>=l)+(j>=l)+(k>=l)+(cur>=l)!=x)
                                     f[i][j][k][o]=0;
                               }
                        }
            }
            
            for(int i=0;i<=n;++i)
                    for(int j=i;j<=n;++j)
                        for(int k=j;k<=n;++k)
                            add(ans,f[i][j][k][n&1]);    
            
            printf("%d
    ",ans);
        }
        
        
        return 0;    
    }
    View Code

    Operation

    题解:https://blog.csdn.net/liufengwei1/article/details/96994017

     1 #include<bits/stdc++.h>
     2 #define maxl 1000010
     3  
     4 using namespace std;
     5  
     6 int n,m,ans;
     7 int a[maxl];
     8 struct LB
     9 {
    10     int p[31],pos[31];
    11     inline void init()
    12     {
    13         for(int i=0;i<=30;i++)
    14             p[i]=0,pos[i]=0;
    15     }
    16     inline void insert(int x,int id)
    17     {
    18         for(int i=30;i>=0;i--)
    19         if(x&(1<<i))
    20         {
    21             if(!p[i])
    22             {
    23                 p[i]=x;
    24                 pos[i]=id;
    25                 return;
    26             }
    27             if(id>pos[i])
    28             {
    29                 swap(x,p[i]);
    30                 swap(id,pos[i]);
    31             }
    32             x^=p[i];
    33         }
    34     }
    35     inline int getmax(int l)
    36     {
    37         int res=0;
    38         for(int i=30;i>=0;i--)
    39         if(pos[i]>=l && (res^p[i])>res)
    40             res^=p[i];
    41         return res;
    42     }
    43 }b[maxl];
    44  
    45 inline void prework()
    46 {
    47     scanf("%d%d",&n,&m);
    48     for(int i=1;i<=n;i++)
    49         scanf("%d",&a[i]);
    50     for(int i=1;i<=n;i++)
    51     {
    52         b[i]=b[i-1];
    53         b[i].insert(a[i],i);
    54     }
    55 }
    56  
    57 inline void mainwork()
    58 {
    59     int l,r,op,x;ans=0;
    60     for(int i=1;i<=m;i++)
    61     {
    62         scanf("%d",&op);
    63         if(op==0)
    64         {
    65             scanf("%d%d",&l,&r);
    66             l=(l^ans)%n+1;
    67             r=(r^ans)%n+1;
    68             if(l>r) swap(l,r);
    69             ans=b[r].getmax(l);
    70             printf("%d
    ",ans);
    71         }
    72         else
    73         {
    74             scanf("%d",&x);
    75             x^=ans;
    76             a[++n]=x;
    77             b[n]=b[n-1];
    78             b[n].insert(a[n],n);
    79         }
    80     }
    81 }
    82  
    83 inline void print()
    84 {
    85 }
    86  
    87 int main()
    88 {
    89     int t;
    90     scanf("%d",&t);
    91     for(int i=1;i<=t;i++)
    92     {
    93         prework();
    94         mainwork();
    95         print();
    96     }
    97     return 0;
    98 }
    View Code

    C Milk 

    Unsolved.

    D Vacation

    题解:题目给出两个人要去旅行,在他们前面有n辆车,每辆车有长度以及车首部到stopline 的距离以及每辆车的最大速度,后面的车不能超过前面的车。问你他们两个的车首部到达stopline的最短时间。

    思路:二分答案,求出最后一辆车停在的位置。

    参考代码:

    #include<bits/stdc++.h>
    using namespace std;
    
    #define mkp make_pair<int,int>
    typedef long long ll;
    const int maxn=2e5+10;
    double eps=1e-12;
    ll n;
    struct Node{
        ll l,s,v;
    } a[maxn];
    int check(double x)
    {
        double ans=a[n].s-a[n].v*x;
        for(int i=n-1;i>=0;i--)
        {
             if(a[i].s-a[i].v*x<=ans+a[i+1].l) ans+=a[i+1].l;
             else ans=a[i].s-a[i].v*x;
        }
        return ans<=eps;
    }
    
    int main()
    {
        while(~scanf("%lld",&n))
        {
             for(int i=0;i<=n;i++) scanf("%lld",&a[i].l);
             for(int i=0;i<=n;i++) scanf("%lld",&a[i].s);
             for(int i=0;i<=n;i++) scanf("%lld",&a[i].v);
             double l=0,r=1e18;
             while(r-l>eps)
             {
                  double mid=(l+r)/2;
                  if(check(mid)) r=mid;
                  else l=mid;
             }
             printf("%.10f
    ",r);
        }
        return 0;
    }
    View Code

    E Path

    题解:给你n个点,m条边(有向边),每天变有一定的权值。让你求删掉一些边使得1到 n 的最短路径变大的最小代价(代价是删除的边的边权之和)。

    思路:先跑一遍最短路求出1到其他点的最短距离,然后 倒着dfs 求出最短路的DAG的所有边,重新建图,跑最小割就行了。

    参考代码:

    #include<bits/stdc++.h>/////////
    #define int long long 
    #define ll long long
    #define lson l,m,rt<<1
    #define rson m+1,r,rt<<1|1
    using namespace std;
    const int MAXN = 10010;
    const int INF=0x3f3f3f3f3f3f3f3fll;
    struct node{
        int to;
        int val;
        int next;
    }edge[MAXN*100*2],e[MAXN*200*5];
    int ind,pre[MAXN],vis[MAXN],dis[MAXN],pre1[MAXN],ind1;
    int now[MAXN],S,T;
    int n,m;
    void add1(int x,int y,int z)
    {
        e[ind1].to = y;
        e[ind1].val = z;
        e[ind1].next = pre1[x];
        pre1[x] = ind1 ++;
    }
    void spfa()
    {
        for(int i = 1; i <= n; i++){
            dis[i] = INF;
            vis[i] = 0;
        }
        vis[T] = 1;
        dis[T] = 0;
        queue<int>q;
        q.push(T);
        while(!q.empty()){
            int tp = q.front();
            q.pop();
            vis[tp] = 0;
            for(int i = pre1[tp]; i != -1; i = e[i].next){
                int t = e[i].to;
                if(dis[t] > dis[tp] + e[i].val){
                    dis[t] = dis[tp] + e[i].val;
                    if(!vis[t]){
                        vis[t] = 1;
                        q.push(t);
                    }
                }
            }
        }
    }
    void add(int x,int y,int z)
    {
        edge[ind].to = y;
        edge[ind].val = z;
        edge[ind].next = pre[x];
        pre[x] = ind ++;
    }
    void dfs1(int rt)
    {
        vis[rt] = 1;
        if(rt == T)return ;
        for(int i = pre1[rt]; i != -1; i = e[i].next){
            int t = e[i].to;
            if(now[rt] + dis[t] + e[i].val == dis[S]){
                now[t] = now[rt] + e[i].val;
                add(rt,t,e[i].val);
                add(t,rt,0);
                if(!vis[t]){
                    dfs1(t);
                }
            }
        }
    }
    int bfs()
    {
        memset(vis,-1,sizeof(vis));
        queue<int>q;
        vis[S] = 0;
        q.push(S);
        while(!q.empty()){
            int tp = q.front();
            q.pop();
            for(int i = pre[tp]; i != -1; i = edge[i].next){
                int t = edge[i].to;
                if(vis[t] == -1 && edge[i].val){
                    vis[t] = vis[tp] + 1;
                    q.push(t);
                }
            }
        }
        if(vis[T] == -1)return 0;
        return 1;
    }
    int dfs(int rt,int low)
    {
        int used = 0;
        if(rt == T)return low;
        for(int i = pre[rt]; i != -1 && used < low; i = edge[i].next){
            int t = edge[i].to;
            if(vis[t] == vis[rt] + 1 && edge[i].val){
                int a = dfs(t,min(low-used,edge[i].val));
                used += a;
                edge[i].val -= a;
                edge[i^1].val += a;
            }
        }
        if(used == 0)vis[rt] = -1;
        return used;
    }
    int x[MAXN*100],y[MAXN*100],z[MAXN*100];
    void Init(int flag)
    {
        ind1 = 0;
        memset(pre1,-1,sizeof(pre1));
        for(int i = 1; i <= m; i++){
            if(!flag){
                add1(y[i],x[i],z[i]);
            }
            else {
                add1(x[i],y[i],z[i]);
            }
        }
    }
    int32_t main()
    {
        int t;
        scanf("%lld",&t);
        while(t--){
            scanf("%lld%lld",&n,&m);
            for(int i = 1; i <= m; i++){
                scanf("%lld%lld%lld",&x[i],&y[i],&z[i]);
            }
            Init(0);
            S=1,T=n;
            spfa();
            Init(1);
            ind = 0;
            memset(now,0,sizeof(now));
            memset(pre,-1,sizeof(pre));
            dfs1(S);
            int ans = 0;
            while(bfs())
            {
                while(1)
                {
                    int a = dfs(S,INF);
                    if(!a)break;
                    ans += a;
                }
            }
            printf("%lld
    ",ans);
        }
        return 0;
    }
    View Code

    F Typewriter

    题解:题目的意思我想要得到一个给定字符串,然后刚开始是空串,有两种操作,1:在后面添加任意的一个字符,代价为p, 2:从前面已经出现过的子串里面赋值一段,放在后面,代价为q;

    让你求得到给定字符串的最小代价。

    思路:对 i 从小到大处理,f[i]: 表示形成前i个字符所需要的最小代价;

    然后对于每一个i,维护 使得  s[j : i] ∈ s[1 : j-1] 的最小的 j(s[l : r] 表示子串sl sl+1 ... sr),那么记 f[i] 为输出前 i 个字符的最小代价,则 f[i] = min{f[i-1]+p, f[j-1]+q}。

    用 SAM 维护 s[1 : j-1],若 s[1 : j-1] 中包含 s[j : i + 1],即加入第 i + 1 个字符仍能复制,就不需要做任何处理。否则,重复地将第 j 个字符加入后缀自动机并 j = j + 1,应维护 s[j : i + 1] 在后缀自动机上新的匹配位置,直到 s[j, i + 1] ∈ s[1, j 1]

    参考代码:

    #include<bits/stdc++.h>
    using namespace std;
    #define pii pair<int,int>
    #define mkp make_pair
    #define fi first
    #define se second
    typedef long long ll;
    const int maxn=2e5+10;
    char s[maxn];
    ll p,q;
    struct SAM{
        int l[maxn<<1],fa[maxn<<1],nxt[maxn<<1][26];
        int cnt,last,rt;
        ll dp[maxn];
        
        void Init()
        {
            cnt=last=rt=1;
            memset(nxt[1],0,sizeof(nxt[1]));
            fa[1]=l[1]=0;
        }
        
        int NewNode()
        {
            cnt++;
            memset(nxt[cnt],0,sizeof(nxt[cnt]));
            fa[cnt]=l[cnt]=0;
            return cnt;    
        }
        
        void Add(int ch)
        {
            int p=last,np=NewNode();
            last=np; l[np]=l[p]+1;
            
            while(p && !nxt[p][ch]) nxt[p][ch]=np,p=fa[p];
            
            if(!p) fa[np]=1;
            else
            {
                int q=nxt[p][ch];
                if(l[p]+1==l[q]) fa[np]=q;
                else
                {
                    int nq=NewNode();
                    memcpy(nxt[nq],nxt[q],sizeof(nxt[q]));
                    fa[nq]=fa[q];
                    l[nq]=l[p]+1;
                    fa[q]=fa[np]=nq;
                    while(nxt[p][ch]==q) nxt[p][ch]=nq,p=fa[p];
                }
            }    
        }
        
        int Match(char ch)
        {
            return nxt[rt][ch-'a'];    
        }
        
        void Search(int len)
        {
            while(rt && l[fa[rt]]>=len) rt=fa[rt];
            if(rt==0) rt=1; 
        }
        
        void work(int len,char ch) 
        {
            rt=nxt[rt][ch-'a'];
            if(rt==0) rt=1;
            Search(len);    
        }
        
        ll DP()
        {
            Init();
            Add(s[0]-'a');
            int l=1,r=0,len=strlen(s);
            dp[0]=p;
            for(int i=1;i<len;++i)
            {
                r++;
                dp[i]=dp[i-1]+p;
                while(!Match(s[i]) || (r-l+1)>(i+1)/2&&l<=r)
                {
                    Add(s[l++]-'a');
                    Search(r-l);
                }    
                work(r-l+1,s[i]);
                if(l<=r) dp[i]=min(dp[i],dp[i-(r-l+1)]+q);
            }
            return dp[len-1];
        }
        
    } sam;   
    
    int main()
    {
        while(~scanf("%s%lld%lld",s,&p,&q)) 
            printf("%lld
    ",sam.DP());
            
        return 0;    
    }
    View Code

    G  Meteor

    Unsolved.

    H Desert

    Unsolved.

    I String

    题解:题目意思是给你一个长度为N的字符串,然后给你一个K,让你求满足条件的字典序最小的长度为K的子序列。

    对于子序列的要求为:(Li,Ri):表示子序列中对应字符的数量应该在这个区间之间

    参考代码:

    #include <bits/stdc++.h>
    using namespace std;
    const int N=2e5+7; 
    char s[N],ans[N];
    int k,n,cnt[N][26],l[26],r[26],used[26],last;
    vector<int> vec[26];
    int main() 
    {
        while(~scanf("%s%d",s,&k)) 
        {
            for(int i=0;i<=25;++i) scanf("%d%d",l+i,r+i);
            n = strlen(s);
            memset(used,0,sizeof(used));
            memset(cnt[n],0,sizeof(cnt[n]));
            for(int i=0;i<26;++i) vec[i].clear();
            for(int i=n-1;i>=0;--i)
                for(int j=0;j<=25;++j)
                    cnt[i][j]=cnt[i+1][j]+(s[i]=='a'+j);
        
            for(int i=0;i<=n-1;++i) vec[s[i]-'a'].push_back(i);
            vector<int>::iterator head[26];
            for(int i=0;i<=25;++i) head[i]=vec[i].begin();
            last=-1;
            bool temp=true;
            for(int i=0;i<=k-1;++i) 
            {
                bool f1=0;
                for(int j=0;j<=25;++j)
                {
                    if(used[j]==r[j]) continue;
                    while(head[j]!=vec[j].end() && (*head[j])<=last) head[j]++;
                    if(head[j]==vec[j].end()) continue;
                    used[j]++;//加上这个位置字符
                    bool flag=1;
                    int pos=(*head[j]),sum=0;
                    //判断已经使用的数量加上后面的剩余的数量是否满足题意
                    for(int t=0;t<=25;++t) 
                    {
                        if(cnt[pos+1][t]+used[t]<l[t]) flag=0;
                        sum+=max(l[t]-used[t],0);
                    }
                    if(sum>k-i-1) flag=0;
                    sum=0;
                    //最多能使用的字符数量
                    for(int t=0;t<=25;++t)
                        sum+=min(cnt[pos+1][t],r[t]-used[t]);
                    if(sum<k-i-1) flag=0;
                    
                    if(!flag) used[j]--;
                    else 
                    {
                        ans[i]='a'+j;
                        f1=1;
                        last=pos;
                        break;
                    }
                }
                if(!f1) { puts("-1");temp=false;break;}
            }
            if(!temp) continue;
            ans[k]='';
            printf("%s
    ",ans);
        }
        return 0;
    }
    View Code

    J - Kingdom

    Unsolved.

    K Function

     Unsolved.

    L Sequence

    Unsolved.

    M Code

    题解:https://blog.csdn.net/liufengwei1/article/details/96900870

    #include<bits/stdc++.h>
    #define maxl 1000010
     
    using namespace std;
     
    int n,m,ans;
    int a[maxl];
    struct LB
    {
        int p[31],pos[31];
        inline void init()
        {
            for(int i=0;i<=30;i++)
                p[i]=0,pos[i]=0;
        }
        inline void insert(int x,int id)
        {
            for(int i=30;i>=0;i--)
            if(x&(1<<i))
            {
                if(!p[i])
                {
                    p[i]=x;
                    pos[i]=id;
                    return;
                }
                if(id>pos[i])
                {
                    swap(x,p[i]);
                    swap(id,pos[i]);
                }
                x^=p[i];
            }
        }
        inline int getmax(int l)
        {
            int res=0;
            for(int i=30;i>=0;i--)
            if(pos[i]>=l && (res^p[i])>res)
                res^=p[i];
            return res;
        }
    }b[maxl];
     
    inline void prework()
    {
        scanf("%d%d",&n,&m);
        for(int i=1;i<=n;i++)
            scanf("%d",&a[i]);
        for(int i=1;i<=n;i++)
        {
            b[i]=b[i-1];
            b[i].insert(a[i],i);
        }
    }
     
    inline void mainwork()
    {
        int l,r,op,x;ans=0;
        for(int i=1;i<=m;i++)
        {
            scanf("%d",&op);
            if(op==0)
            {
                scanf("%d%d",&l,&r);
                l=(l^ans)%n+1;
                r=(r^ans)%n+1;
                if(l>r) swap(l,r);
                ans=b[r].getmax(l);
                printf("%d
    ",ans);
            }
            else
            {
                scanf("%d",&x);
                x^=ans;
                a[++n]=x;
                b[n]=b[n-1];
                b[n].insert(a[n],n);
            }
        }
    }
     
    inline void print()
    {
    }
     
    int main()
    {
        int t;
        scanf("%d",&t);
        for(int i=1;i<=t;i++)
        {
            prework();
            mainwork();
            print();
        }
        return 0;
    }
    View Code

    后面的题解慢慢更新~


  • 相关阅读:
    机器学习——模型评估与选择
    论文等级
    python简介
    记忆力
    PyQt 5控件
    PyQt5对话框
    PyQt 5事件和信号
    PyQt 5菜单和工具栏
    PyQt 5布局管理
    PyQt 5的基本功能
  • 原文地址:https://www.cnblogs.com/csushl/p/11229659.html
Copyright © 2011-2022 走看看