2019.3.18考试&2019.3.19考试&2019.3.21考试

2019.3.18

C O D E

T1

树上直接贪心,环上for一遍贪心


哇说的简单,码了将近一下午终于码出来了

想好了就果断写啊

废话结束


对于入度大于一且不在环上的点直接贪心留最大的

对于一个完美无瑕的环直接断最小的(指没有被环以外的点指着)

对于入度大于一且在环上的点,先假装它就是普通的入度大于一的点来做并记录每个点是否断了环上的边和断的边中的最大值;最后把没有删边的不完美的环每个单独拿出来,枚举到底断那一条边修正答案

细节不说了,这种题的细节也没啥可说的。。。

(为了避免伤害眼睛已经删掉了调试语句

  1 #include<cstdio>
  2 #include<vector>
  3 #include<cstring>
  4 #include<algorithm>
  5 #define vint vector<int>
  6 #define vit vector<int>::iterator
  7 using namespace std;
  8 const int N=100005;
  9 int p[N],noww[N],goal[N];
 10 int rec[N],cst[N],inc[N],col[N];
 11 int deg[N],aset[N],stk[N],vis[N];
 12 int cal[N],cut[N],brk[N],spe[N],mae[N];
 13 int n,dfn,cnt,tot,top; long long ans; vint ve[N],cr[N];
 14 void Link(int f,int t)
 15 {
 16     noww[++cnt]=p[f];
 17     goal[cnt]=t,p[f]=cnt;
 18 }
 19 int Finda(int x)
 20 {
 21     return x==aset[x]?x:aset[x]=Finda(aset[x]);
 22 }
 23 bool Bigcir()
 24 {
 25     int tmp=0;
 26     for(int i=1;i<=n;i++)
 27     {
 28         if(Finda(i)==i) tmp++;
 29         if(deg[i]!=1) return false;
 30     }
 31     return tmp==1;
 32 }
 33 void DFS(int nde)
 34 {
 35     stk[++top]=nde,vis[nde]=dfn;
 36     for(int i=p[nde],g;i;i=noww[i])
 37         if(!vis[g=goal[i]]) DFS(g);
 38         else if(vis[g]==dfn)
 39         {
 40             int ori=g,pts=top; tot++;
 41             while(stk[pts]!=ori)
 42             {
 43                 int tmp=stk[pts--];
 44                 cr[tot].push_back(tmp);
 45                 col[tmp]=tot,inc[tmp]=true;
 46             }
 47             cr[tot].push_back(ori);
 48             col[ori]=tot,inc[ori]=true;
 49         }
 50     top--;
 51 }
 52 int main()
 53 {
 54     scanf("%d",&n);
 55     for(int i=1;i<=n;i++) aset[i]=i;
 56     for(int i=1;i<=n;i++)
 57     {
 58         scanf("%d%d",&rec[i],&cst[i]);
 59         Link(i,rec[i]),ve[rec[i]].push_back(i);
 60         aset[Finda(i)]=Finda(rec[i]),deg[rec[i]]++;
 61     }
 62     if(Bigcir()) printf("0"),exit(0);
 63     else
 64     {
 65         cst[n+1]=1e9;
 66         for(int i=1;i<=n;i++)
 67             if(!vis[i]) dfn++,DFS(i);
 68         for(int i=1;i<=n;i++)
 69             if(deg[i]>1&&inc[i])
 70             {
 71                 int t,o=0,c=col[i],kao;
 72                 for(vit it=ve[i].begin();it!=ve[i].end();it++) 
 73                 {
 74                     if(!cut[t=*it]&&cst[t]>cst[o]) o=t;
 75                     if(inc[t]) kao=t;
 76                 }
 77                 for(vit it=ve[i].begin();it!=ve[i].end();it++) 
 78                     if(!cut[t=*it]&&t!=o)     
 79                     {
 80                         cut[t]=true,mae[i]=max(mae[i],cst[t]);    
 81                         if(t==kao) brk[c]=true;
 82                     }
 83                 cal[c]=true,spe[i]=true;
 84             }
 85         for(int i=1;i<=n;i++) 
 86             if(deg[i]>1&&!inc[i])
 87             {
 88                 int t,o=0; 
 89                 for(vit it=ve[i].begin();it!=ve[i].end();it++) 
 90                     if(!cut[t=*it]&&cst[t]>cst[o]) o=t;
 91                 for(vit it=ve[i].begin();it!=ve[i].end();it++) 
 92                     if((t=*it)!=o) cut[t]=true,deg[rec[t]]--;
 93             }
 94         for(int i=1;i<=tot;i++)
 95             if(!cal[i])
 96             {
 97                 int t,o=n+1;
 98                 for(vit it=cr[i].begin();it!=cr[i].end();it++) 
 99                     if(!cut[(t=*it)]&&cst[t]<cst[o]) o=t;
100                 cut[o]=true,deg[rec[o]]--;
101             }
102     }
103     for(int i=1;i<=n;i++) 
104         if(cut[i]) ans+=cst[i];
105     for(int i=1;i<=tot;i++)
106         if(cal[i]&&!brk[i])
107         {
108             int t; long long tep=1e18;
109             for(vit it=cr[i].begin();it!=cr[i].end();it++)
110                 if(!spe[rec[t=*it]]) tep=min(tep,ans+cst[t]);
111                 else tep=min(tep,ans+cst[t]-mae[rec[t]]);
112             ans=tep;
113         }
114     printf("%lld",ans);
115     return 0;
116 }
View Code

T2

逐行地每次正反都做一遍DP,记录从哪里吃过来,对应地递归吃后面的

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<algorithm>
 4 using namespace std;
 5 const int N=405,inf=0x3f3f3f3f;
 6 int n,m,vis[N][N],dp[N][N];
 7 char str[N][N];
 8 void Mini(int &x,int y)
 9 {
10     if(x>y) x=y;
11 }
12 bool Out(int a,int b)
13 {
14     return a<1||b<1||a>n||b>m;
15 }
16 int DFS(int x,int y,int t)
17 {
18     if(Out(x,y)) return 0;
19     int &vs=vis[x][y];
20     if(~vs) return vs?0:inf;
21     vs=0; int ret=2;
22     if(str[x][y]=='Z')
23     {
24         if(t<2) ret+=DFS(x+1,y,0)+DFS(x,y+1,1);
25         else ret+=DFS(x-1,y,2)+DFS(x,y-1,3);
26         Mini(ret,inf);
27     }
28     else
29     {
30         if(t==1||t==2) ret+=DFS(x,y+1,1)+DFS(x-1,y,2);
31         else ret+=DFS(x+1,y,0)+DFS(x,y-1,3);
32         Mini(ret,inf);
33     }
34     if(ret!=inf) vs=1;
35     return ret;
36 }
37 int main()
38 {
39     scanf("%d%d",&n,&m);
40     for(int i=1;i<=n;i++)
41         scanf("%s",str[i]+1);
42     memset(dp,0x3f,sizeof dp);
43     for(int i=1;i<=n;i++)
44     {
45         memset(vis,-1,sizeof vis);
46         for(int j=1,t=0;j<=m;j++)
47             t+=DFS(i,j,3),Mini(t,inf),Mini(dp[i][j],t);
48         memset(vis,-1,sizeof vis);
49         for(int j=m,t=0;j;j--)
50             t+=DFS(i,j,1),Mini(t,inf),Mini(dp[i][j],t);
51     }
52     for(int i=1;i<=n;i++)
53         for(int j=1;j<=m;j++)
54         {
55             if(dp[i][j]==inf) printf("-1"); 
56             else printf("%d",dp[i][j]);
57                         j==m?puts(""):putchar(' ');
58         }
59     return 0;
60 }
View Code

T3

观察到顺序不影响答案,分块打标记

注意分开处理两边零散块是有顺序的

(已经忘掉有分块这个东西了TAT

 1 #pragma GCC optimize(3)
 2 #include<queue>
 3 #include<cstdio>
 4 #include<cstring>
 5 #include<algorithm>
 6 #define vint vector<int>
 7 #define gint greater<int> 
 8 #define prq priority_queue
 9 using namespace std;
10 const int N=400005,Sq=660;
11 int n,m,rd,lp,rp,tg,sqr,tot;
12 int sus[N],bel[N],lpt[Sq],rpt[Sq];
13 prq<int> mxx[Sq]; prq<int,vint,gint> tag[Sq];
14 void Pre()
15 {
16     sqr=sqrt(n)+5,lpt[tot=1]=1;
17     for(int i=1;i<=n;i++)
18     {
19         bel[i]=(i-1)/sqr+1;
20         if(i%sqr==0) rpt[tot++]=i,lpt[tot]=i+1;
21     }
22     n%sqr?rpt[tot]=n:tot--;
23 }
24 void Create(int b)
25 {
26     mxx[b]=prq<int> ();
27     for(int i=lpt[b];i<=rpt[b];i++) mxx[b].push(sus[i]);
28 }
29 void Release(int b)
30 {
31     if(!tag[b].empty())
32     {
33         for(int i=lpt[b];i<=rpt[b];i++)
34             if(tag[b].top()<sus[i])
35                 tag[b].push(sus[i]),sus[i]=tag[b].top(),tag[b].pop();
36     }
37     tag[b]=prq<int,vint,gint> ();
38 }
39 int Round(int l,int r,int s)
40 {
41     if(bel[l]==bel[r])
42     {
43         int b=bel[l]; 
44         Release(b);
45         for(int i=l;i<=r;i++)
46             if(s<sus[i]) swap(s,sus[i]);
47         Create(b);    
48     }
49     else
50     {
51         int b1=bel[l],b2=bel[r];
52         Release(b1);
53         for(int i=l;i<=rpt[b1];i++)
54             if(s<sus[i]) swap(s,sus[i]); Create(b1);
55         for(int i=b1+1;i<=b2-1;i++)
56             if(s<mxx[i].top())
57             {
58                 int tmp=mxx[i].top(); mxx[i].pop();
59                 mxx[i].push(s),tag[i].push(s),s=tmp;
60             } 
61         Release(b2);
62         for(int i=lpt[b2];i<=r;i++)
63             if(s<sus[i]) swap(s,sus[i]); Create(b2);
64     }
65     return s;
66 }
67 int main()
68 {
69     scanf("%d%d",&n,&m),Pre();
70     for(int i=1;i<=n;i++) scanf("%d",&sus[i]);
71     for(int i=1;i<=tot;i++) Create(i);
72     for(int i=1;i<=m;i++)
73     {
74         scanf("%d%d%d",&lp,&rp,&tg);
75         if(lp>rp) tg=Round(lp,n,tg),lp=1;
76         printf("%d
",Round(lp,rp,tg));
77     }
78     return 0;
79 }
View Code

2019.3.19

肥肠爆芡,因为沙茶博主昨天在沙茶学校的沙茶食堂吃坏了肚子,所以这场考试咕咕了

开始补档

T1

一开始找x坐标或y坐标最大的点,然后看下一次转向,左转就走极角最大的,右转就走极角最小的

其实扫一遍就可以,然而我傻乎乎地每次都排了个序

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<algorithm>
 4 using namespace std;
 5 const int N=5005;
 6 struct a{int xp,yp,idx;}o,pt[N],cp[N];
 7 bool cmp(a x,a y)
 8 {
 9     return x.xp==y.xp?x.yp<y.yp:x.xp<y.xp;
10 }
11 long long Cha(a x,a y)
12 {
13     return 1ll*(x.xp-o.xp)*(y.yp-o.yp)-1ll*(y.xp-o.xp)*(x.yp-o.yp);
14 }
15 bool cop(a x,a y)
16 {
17     return Cha(x,y)<0;
18 }
19 int n,m,vis[N],ans[N]; char str[N];
20 void Solve(int p,int l,int r,a q)
21 {
22     vis[q.idx]=true,ans[p]=q.idx; 
23     if(p==n) return;
24     o=q,sort(cp+l,cp+1+r,cop);
25     if(str[p]=='L') Solve(p+1,l,r-1,cp[r]);
26     else Solve(p+1,l+1,r,cp[l]);
27 }
28 int main()
29 {
30     scanf("%d",&n);
31     for(int i=1;i<=n;i++)
32         scanf("%d%d",&pt[i].xp,&pt[i].yp),pt[i].idx=i;
33     scanf("%s",str+1);
34     sort(pt+1,pt+1+n,cmp);
35     for(int i=1;i<=n;i++) cp[i]=pt[i];
36     Solve(1,1,n-1,pt[n]);
37     for(int i=1;i<=n;i++) printf("%d ",ans[i]);
38     return 0;
39 }
View Code

T2 

推性质题,我们发现每个人感染的是一段区间的人,然后就转成了线段覆盖的方案数,树状数组优化

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<algorithm>
 4 #define vint vector<int>
 5 #define vit vector<int>::iterator
 6 using namespace std;
 7 const int N=200005,mod=1e9+7;
 8 int n,ans,uni[N],spd[N],bit[N],pre[N],suf[N];
 9 struct a{int pos,spe;}pt[N]; vint ve[N];
10 bool cmp(a x,a y){return x.pos<y.pos;}
11 void Add(int &x,int y){x+=y; if(x>=mod) x-=mod;}
12 void Modify(int x,int y)
13 {
14     while(x<=n)
15         Add(bit[x],y),x+=x&-x;
16     return;
17 }
18 int Query(int x)
19 {
20     int ret=0;
21     while(x>0)
22         Add(ret,bit[x]),x-=x&-x;
23     return ret;
24 }
25 int main()
26 {
27     register int i;
28     scanf("%d",&n);
29     for(i=1;i<=n;i++)
30         scanf("%d%d",&pt[i].pos,&pt[i].spe),uni[i]=pt[i].spe;
31     sort(pt+1,pt+1+n,cmp),sort(uni+1,uni+1+n);
32     int lth=unique(uni+1,uni+1+n)-uni-1;
33     for(i=1;i<=n;i++) spd[i]=lower_bound(uni+1,uni+1+lth,pt[i].spe)-uni;
34     for(i=1;i<=n;i++) pre[i]=max(pre[i-1],spd[i]);
35     for(i=n,suf[n+1]=1e9;i;i--) suf[i]=min(suf[i+1],spd[i]);
36     for(int i=1;i<=n;i++) ve[pre[i]].push_back(suf[i]);
37     for(int i=1,t,tmp;i<=n;i++)
38         for(vit it=ve[i].begin();it!=ve[i].end();it++)
39         {
40             t=*it,tmp=(Query(i)-Query(t-2)+(t<2)+mod)%mod;
41             Modify(i,tmp); if(i==n) Add(ans,tmp);
42         }
43     printf("%d",ans);    
44     return 0;
45 }
View Code

T3

这题......

(orz ztb tql)

2019.3.21

T1

容斥/点分治

咕咕咕

T2

转化成完全二分图的哈密顿回路

然后考场推到这里不会去重,搞出来一个整数划分,没了

去重的方法是我们选定第一个回路经过左边第一个,然后就有

T3

orz yzh tql

模拟费用流,在每一只鸟进来之后找离这只鸟最近的还有空的点,正确性参考费用流

具体来说要支持树上边权取反和查询到所有合法点的最短路,因为树高只有log,暴力爬树维护

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<algorithm>
 4 using namespace std;
 5 const int N=300005,inf=1e9;
 6 int nes[N],gu[N],flw[N],dp[N],bes[N],n,m,ans;
 7 void Maintain(int nde)
 8 {
 9     int ls=2*nde,rs=2*nde+1; dp[nde]=inf;
10     if(ls<=n&&dp[ls]+(flw[ls]>=0?1:-1)<dp[nde]) 
11         dp[nde]=dp[ls]+(flw[ls]>=0?1:-1),bes[nde]=bes[ls];
12     if(rs<=n&&dp[rs]+(flw[rs]>=0?1:-1)<dp[nde]) 
13         dp[nde]=dp[rs]+(flw[rs]>=0?1:-1),bes[nde]=bes[rs];
14     if(nes[nde]&&dp[nde]>=0) dp[nde]=0,bes[nde]=nde;
15 }
16 void Pushup(int nde)
17 {
18     Maintain(nde); 
19     if(nde!=1) Pushup(nde>>1);
20 }
21 void Gu(int nde)
22 {
23     int x=nde,tmp=0,bsf=inf,bsp=0,bsn=0;
24     while(x)
25     {
26         int tep=tmp+dp[x];
27         if(tep<bsf) bsf=tep,bsp=bes[x],bsn=x;
28         tmp+=(flw[x]<=0?1:-1),x>>=1;
29     }
30     ans+=bsf,nes[bsp]--;
31     int mem1=nde,mem2=bsp;
32     while(nde!=bsn) flw[nde]--,nde>>=1; 
33     while(bsp!=bsn) flw[bsp]++,bsp>>=1;
34     Pushup(mem1),Pushup(mem2);
35 }
36 int main()
37 {
38     scanf("%d%d",&n,&m);
39     for(int i=1;i<=n;i++) scanf("%d",&nes[i]);
40     for(int i=1;i<=m;i++) scanf("%d",&gu[i]);
41     for(int i=n;i;i--) Maintain(i);
42     for(int i=1;i<=m;i++) Gu(gu[i]),printf("%d ",ans);
43     return 0;
44 }
View Code
原文地址:https://www.cnblogs.com/ydnhaha/p/10558495.html