2019 杭电多校第一场


 

总结:

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

题意问题

try a try. 1e4dinic冲冲冲

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

比赛不要划水聊天

 


 

题解:

A Blank

 Unsolved.

 

Operation

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

 

 1 #include
 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\n",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
using namespace std;

#define mkp make_pair
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\n",r);
    }
    return 0;
}
View Code

E Path

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

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

参考代码:

 

#include/////////
#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\n",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
using namespace std;
#define pii pair
#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;ii)
        {
            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\n",sam.DP());
        
    return 0;    
}
View Code

 

G  Meteor

Unsolved.

 

H Desert

Unsolved.

I String

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

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

参考代码:

#include 
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]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(sum1) 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]='\0';
        printf("%s\n",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
#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\n",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

 

 

后面的题解慢慢更新~

 


 

你可能感兴趣的:(2019 杭电多校第一场)