2019多校 7.24

6592 Beauty Of Unimodal Sequence

线段树优化dp
f0[i]代表必须下降,f1[i]代表后缀下降剩下的前缀上升
同时维护f数组最优情况下的最靠左最靠右转移点

#include <queue>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define rep(i,l,r) for(int i=l;i<=r;++i)
#define per(i,l,r) for(int i=l;i>=r;--i)
using namespace std;
typedef long long s64;

const int M=3e5+5;
int n;
int a[M];
int f0[M],f1[M],L0[M],R0[M],L1[M],R1[M];
int Max[2][M*4],L[2][M*4],R[2][M*4];
int ans[3];

struct node {
     int x,id;

     bool operator <(const node &a) const {
          return x<a.x;
     }
}p[M];

void T_add(int g,int l,int r,int x,int y) {
     if(l==r) {
          if(f0[y]>Max[0][g]) {
               Max[0][g]=f0[y];
               L[0][g]=R[0][g]=y;
          }
          else if(f0[y]==Max[0][g]) {
               L[0][g]=min(L[0][g],y);
               R[0][g]=max(R[0][g],y);
          }

          if(f1[y]>Max[1][g]) {
               Max[1][g]=f1[y];
               L[1][g]=R[1][g]=y;
          }
          else if(f1[y]==Max[1][g]) {
               L[1][g]=min(L[1][g],y);
               R[1][g]=max(R[1][g],y);
          }

          return;
     }

     int mid=(l+r)>>1;
     if(x<=mid) T_add(g<<1,l,mid,x,y);
     else       T_add(g<<1|1,mid+1,r,x,y);

     int ls=g<<1,rs=g<<1|1;
     if(Max[0][ls]<Max[0][rs]) swap(ls,rs);
     
     Max[0][g]=Max[0][ls];
     L[0][g]=L[0][ls],R[0][g]=R[0][ls];
     if(Max[0][ls]==Max[0][rs]) {
          L[0][g]=min(L[0][g],L[0][rs]);
          R[0][g]=max(R[0][g],R[0][rs]);
     }



     if(Max[1][ls]<Max[1][rs]) swap(ls,rs);
     
     Max[1][g]=Max[1][ls];
     L[1][g]=L[1][ls],R[1][g]=R[1][ls];
     if(Max[1][ls]==Max[1][rs]) {
          L[1][g]=min(L[1][g],L[1][rs]);
          R[1][g]=max(R[1][g],R[1][rs]);
     }
}

void query(int g,int l,int r,int lx,int rx,int opt) {
     //cout<<g<<" "<<l<<" "<<r<<endl;
     if(lx>rx) return;
     if(lx<=l&&rx>=r) {
          if(Max[opt][g]>ans[0]) {
               ans[0]=Max[opt][g];
               ans[1]=L[opt][g];
               ans[2]=R[opt][g];
          } 
          else if(Max[opt][g]==ans[0]) {
               ans[1]=min(ans[1],L[opt][g]);
               ans[2]=max(ans[2],R[opt][g]);
          }
          return;
     }

     int mid=(l+r)>>1;
     if(lx<=mid) query(g<<1,l,mid,lx,rx,opt);
     if(rx>mid)  query(g<<1|1,mid+1,r,lx,rx,opt);
}

void find_min() {
     int da=0;
     rep(i,1,n) da=max(da,f0[i]),da=max(da,f1[i]);

     int pre;
     rep(i,1,n) if(f0[i]==da||f1[i]==da) {pre=i;break;}

     if(da==1) return printf("%d\n",pre),void();

     printf("%d ",pre);
     bool vis=0;
     rep(i,2,da) {
          if(f0[pre]==f1[pre]&&!vis) {
               if(L1[pre]<L0[pre]) vis=1;
               pre=min(L0[pre],L1[pre]);
          }
          else if(f1[pre]==da-i+2) {
               pre=L1[pre];
               vis=1;
          }
          else if(f0[pre]==da-i+2) {
               pre=L0[pre];
          }
          if(i!=da) printf("%d ",pre);
          else printf("%d\n",pre);
     }
}

void find_max() {
     int da=0;
     rep(i,1,n) da=max(da,f0[i]),da=max(da,f1[i]);

     int pre;
     per(i,n,1) if(f0[i]==da||f1[i]==da) {pre=i;break;}

     if(da==1) return printf("%d\n",pre),void();

     printf("%d ",pre);
     bool vis=0;
     rep(i,2,da) {
          if(f0[pre]==f1[pre]&&!vis) {
               if(R1[pre]>R0[pre]) vis=1;
               pre=max(R0[pre],R1[pre]);
          }
          else if(f1[pre]==da-i+2) {
               pre=R1[pre];
               vis=1;
          }
          else if(f0[pre]==da-i+2) {
               pre=R0[pre];
          }
          if(i!=da) printf("%d ",pre);
          else printf("%d\n",pre);
     }
}

int main() {
     //freopen("a.txt","r",stdin);
     //freopen("a.out","w",stdout);
     while (scanf("%d",&n)==1) {
          rep(i,1,n) scanf("%d",a+i);
          rep(i,1,n) p[i]=(node){a[i],i};

          int cnt=0;
          sort(p+1,p+n+1);
          p[0].x=p[1].x-1;
          rep(i,1,n) {
               if(p[i].x!=p[i-1].x) ++cnt;
               a[p[i].id]=cnt; 
          }

          //rep(i,1,n) cout<<a[i]<<" "; cout<<endl;

          per(i,n,1) {
               //cout<<i<<endl;
               ans[0]=0;
               query(1,1,n,1,a[i]-1,1);
               f1[i]=ans[0]+1;
               L1[i]=ans[1],R1[i]=ans[2];


               ans[0]=0;
               query(1,1,n,a[i]+1,n,1);
               query(1,1,n,a[i]+1,n,0);
               f0[i]=ans[0]+1;
               L0[i]=ans[1],R0[i]=ans[2];

               T_add(1,1,n,a[i],i);
          }

          find_min();
          find_max();

          rep(i,1,4*n) Max[0][i]=Max[1][i]=0;
     }
}

6595 Everything Is Generated In Equal Probability

我的做法是线性的
根据期望的线性行只考虑一个逆序对(i,j)的贡献即可
dp发现长度为n的逆序对贡献都是 4 3 \frac {4} {3} 34
直接算即可

#include <queue>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define rep(i,l,r) for(int i=l;i<=r;++i)
#define per(i,l,r) for(int i=l;i>=r;--i)
using namespace std;
typedef long long s64;

const int M=3e3+5;
const int mod=998244353;
int n;
int f[M],bin[M];
int fac[M],inv[M];

int qpow(int x,int k) {
     int t=1;
     for(;k;k>>=1,x=1ll*x*x%mod) if(k&1) t=1ll*t*x%mod;
     return t;
}

int C(int x,int y) {
     if(x<y) return 0;
     return 1ll*fac[x]*inv[y]%mod*inv[x-y]%mod;
}

void inc(int &x,int y) {x+=y,x-=x>=mod?mod:0;}

int main() {
     //freopen("a.txt","r",stdin);
     //freopen("a.out","w",stdout);

     //cout<<554580197ll*9%mod<<endl;

     f[1]=0;

     bin[0]=1;
     rep(i,1,3000) inc(bin[i]=bin[i-1],bin[i-1]);

     fac[0]=1;
     rep(i,1,3000) fac[i]=1ll*i*fac[i-1]%mod;
     inv[3000]=qpow(fac[3000],mod-2);
     per(i,3000,1) inv[i-1]=1ll*i*inv[i]%mod;


     //神奇为啥f[i]都相等呢
     /*
     rep(i,2,3000) {
          rep(j,2,i-1) inc(f[i],1ll*f[j]*C(i-2,i-j)%mod);
          inc(f[i],bin[i]);
          f[i]=1ll*f[i]*qpow(bin[i]-1,mod-2)%mod;
     }
     */

     //rep(i,1,10) cout<<f[i]<<" "; cout<<endl;

     rep(i,2,3000) 
     	inc(f[i]=f[i-1],1ll*C(i,2)*C(i,2)%mod*fac[i-2]%mod*332748119%mod*inv[i]%mod);
     while (scanf("%d",&n)==1) printf("%lld\n",1ll*f[n]*qpow(n,mod-2)%mod);
}

6598 Harmonious Army

类似文理分科的网络流最小割
将每个人worrier + b 4 +\frac{b} {4} +4b,Mage+ c 3 \frac{c}{3} 3c
剩下的按照文理分科来搞
注意worrier和mage要加上inf保证最小割一定会割
即不选择 b 2 + c 3 \frac{b}{2}+\frac{c}{3} 2b+3c的贡献

#include <queue>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define rep(i,l,r) for(int i=l;i<=r;++i)
#define per(i,l,r) for(int i=l;i>=r;--i)
using namespace std;
typedef long long s64;

const int M=2e4+2000;
const int mod=998244353;
const s64 inf=1e15;
int n,m,S,T;
int e_size,head[M];
int dep[M];

s64 A[M],B[M];

struct edge{
     int u;
     int v;
     s64 w;
     int nxt;
}e[M*100];

void e_add(int u,int v,s64 w) {
     e[++e_size]=(edge){u,v,w,head[u]};
     head[u]=e_size;
}

void insert(int u,int v,s64 w) {
     e_add(u,v,w),e_add(v,u,0);
}

bool Bfs() {
     queue <int> q;
     memset(dep,0,sizeof(T)*(T+5));

     q.push(S);
     dep[S]=1;
     while (!q.empty()) {
          int r=q.front();
          q.pop();
          for(int i=head[r];i;i=e[i].nxt) {
               int v=e[i].v;
               if(e[i].w&&!dep[v]) {
                    dep[v]=dep[r]+1;
                    if(v==T) return 1;
                    q.push(v);
               }
          }
     }
     return 0;
}

s64 Dfs(int x,s64 cp) {
     if(x==T) return cp;
     s64 las=cp,q;
     for(int i=head[x];i;i=e[i].nxt) {
          int v=e[i].v;
          if(dep[v]==dep[x]+1&&e[i].w&&las) {
               q=Dfs(v,min(e[i].w,las));
               if(!q) {dep[v]=0;continue;}
               las-=q,e[i].w-=q,e[i^1].w+=q;
          }
     }
     return cp-las;
}

int main() {
     //freopen("a.txt","r",stdin);
     //freopen("a.out","w",stdout);
     while (scanf("%d%d",&n,&m)==2) {

          S=2*(n+m)+1,T=S+1;
          e_size=1;
          int cnt=2*n;
          s64 ans=0;

          rep(i,1,n) A[i]=B[i]=1e12;
          rep(i,1,m) {
               int u,v,a,b,c;
               scanf("%d%d%d%d%d",&u,&v,&a,&b,&c);
               ans+=a+c;

               A[u]+=a/4,A[v]+=a/4;
               B[u]+=c/3,B[v]+=c/3;

               ++cnt;
               insert(S,cnt,a/2);
               insert(cnt,2*u,inf);
               insert(cnt,2*v,inf);

               ++cnt;
               insert(cnt,T,c/3);
               insert(2*u-1,cnt,inf);
               insert(2*v-1,cnt,inf);
          }


          rep(i,1,n) insert(S,2*i-1,A[i]),insert(2*i-1,2*i,inf),insert(2*i,T,B[i]);

          while (Bfs()) ans-=Dfs(S,inf);
          ans+=1e12*n;
          cout<<ans<<endl;

          rep(i,1,T) A[i]=B[i]=head[i]=0;
     }
}

6599 I Love Palindrome String

直接回文自动机算出现次数
dfs回文树用dfs性质判断 v i s [ l e n + 1 2 ] vis[\frac{len+1}{2}] vis[2len+1]是否存在即可

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define rep(i,l,r) for(int i=l;i<=r;++i)
#define per(i,l,r) for(int i=l;i>=r;--i)
using namespace std;
typedef long long s64;


const int M=1e6+5;
int n;
char s[M];
int fail_[M];
bool vis[M];
int ans[M],len[M];
int head[M],e_size;
int node_num,nxt[M][26],f[M],las;

struct edge{
     int v,nxt;
}e[M*2];


void e_add(int u,int v) {
     e[++e_size]=(edge) {v,head[u]};
     head[u]=e_size;
}

int get_fail(int x,int c) {
     while (s[n]!=s[n-len[x]-1]) x=fail_[x];
     return x;
}

void extend_(int c) {
     int t=get_fail(las,c);     
     if(!nxt[t][c]) {
          ++node_num;
          len[node_num]=len[t]+2;
          fail_[node_num]=nxt[get_fail(fail_[t],c)][c];
          nxt[t][c]=node_num;
     }
     las=nxt[t][c];
}

void dfs(int x) {
     if(x!=1) vis[len[x]]=1;


     for(int i=head[x];i;i=e[i].nxt) {
          int v=e[i].v;
          dfs(v);
          f[x]+=f[v];
     }
     if(vis[(1+len[x])>>1]) ans[len[x]]+=f[x];
     
     
     if(x!=1) vis[len[x]]=0;
}

int main() {
     //freopen("a.txt","r",stdin);
     while (scanf("%s",s+1)==1) {
          s[0]=-1;

          fail_[0]=1;
          fail_[1]=1;
          len[1]=-1;
          las=1;
          node_num=1;

          int tot=strlen(s+1);
          reverse(s+1,s+tot+1);
          n=0;
          rep(i,1,tot) {
               ++n;
               extend_(s[i]-'a');
               ++f[las];
          }


          rep(i,0,node_num) if(fail_[i]!=i) e_add(fail_[i],i);

          dfs(1);

          rep(i,1,tot-1) printf("%d ",ans[i]);
          printf("%d\n",ans[tot]);
          e_size=0;
          rep(i,0,node_num) f[i]=head[i]=ans[i]=fail_[i]=0,memset(nxt[i],0,sizeof(nxt[i]));
          node_num=0;
     }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
毕业设计,基于SpringBoot+Vue+MySQL开发的公寓报修管理系统,源码+数据库+毕业论文+视频演示 现代经济快节奏发展以及不断完善升级的信息化技术,让传统数据信息的管理升级为软件存储,归纳,集中处理数据信息的管理方式。本公寓报修管理系统就是在这样的大环境下诞生,其可以帮助管理者在短时间内处理完毕庞大的数据信息,使用这种软件工具可以帮助管理人员提高事务处理效率,达到事半功倍的效果。此公寓报修管理系统利用当下成熟完善的Spring Boot框架,使用跨平台的可开发大型商业网站的Java语言,以及最受欢迎的RDBMS应用软件之一的MySQL数据库进行程序开发。公寓报修管理系统有管理员,住户,维修人员。管理员可以管理住户信息和维修人员信息,可以审核维修人员的请假信息,住户可以申请维修,可以对维修结果评价,维修人员负责住户提交的维修信息,也可以请假。公寓报修管理系统的开发根据操作人员需要设计的界面简洁美观,在功能模块布局上跟同类型网站保持一致,程序在实现基本要求功能时,也为数据信息面临的安全问题提供了一些实用的解决方案。可以说该程序在帮助管理者高效率地处理工作事务的同时,也实现了数据信息的整体化,规范化与自动化。 关键词:公寓报修管理系统;Spring Boot框架;MySQL;自动化;VUE
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值