• 2017/9/22模拟赛


    题解:其实,我们可以把mod3余1、2、0的数分成3组,那么在mod3余1和2的集合中选出较大的,并在mod3余0的集合中随便加入一个数(如果有的话),这样就解决了任意2个数加起来不被3整除的条件了,对于不能被m个数整除的条件,跑一遍筛法,虽然复杂度很玄学,但是这样暴力能拿到很理想的分数--Jimmy。

    代码如下:(暴力)

     1 #include<cstdio>
     2 #include<iostream>
     3 #include<map>
     4 using namespace std;
     5 map<int,int> f;
     6 int cnt[3],n,m,a[20];
     7 void prime(){
     8      for(int i=1;i<=m;i++)
     9         for(int j=1;j*a[i]<=n;j++)
    10             if(!f[a[i]*j]){
    11                 f[a[i]*j]=1;
    12                 --cnt[(a[i]*j)%3];
    13             }
    14 }
    15 int main(){
    16     freopen("overweight.in","r",stdin);
    17     freopen("overweight.out","w",stdout);
    18     scanf("%d%d",&n,&m);
    19     for(int i=1;i<=m;i++){
    20         scanf("%d",&a[i]);
    21         if(a[i]==1){printf("0");return 0;}
    22     }
    23     cnt[0]=cnt[1]=cnt[2]=n/3;
    24     if(n%3==1) ++cnt[1];
    25     if(n%3==2){++cnt[1];++cnt[2];}
    26     prime();
    27     printf("%d",min(1,cnt[0])+max(cnt[1],cnt[2]));
    28     return 0;
    29 }

     

     题解:这题是最大闭合子图,首先我们发现以下性质:①一个骑士移动后,横纵坐标之和的奇偶性会改变;②负权边可以直接扔掉,对答案不会影响。那么,我们就可以把s向所有奇数边连一条权值为x的边,所有偶数边向t连一条权值为x的边,所有奇数边能拓展到的非负权边连一条权值为INF的边,求它的最小割,用非负权边之和-最小割即为答案。

    代码如下:

     1 #include<cstdio>
     2 #include<iostream>
     3 #include<algorithm>
     4 #include<cstring>
     5 #define MN 500005
     6 #define INF 0x7fffffff
     7 using namespace std;
     8 int dx[8]={-2,-2,-1,-1,1,1,2,2},dy[8]={-1,1,-2,2,-2,2,-1,1};
     9 struct edge{int to,cap,next,rev;}e[MN];
    10 int s,t,m,n,cnt,head[MN],lev[MN],q[MN],sum;
    11 void ins(int u,int v,int w){ 
    12     e[++cnt].to=v;e[cnt].next=head[u];head[u]=cnt;e[cnt].cap=w;e[cnt].rev=cnt+1;
    13     e[++cnt].to=u;e[cnt].next=head[v];head[v]=cnt;e[cnt].cap=0;e[cnt].rev=cnt-1;
    14 } 
    15 bool bfs(){ 
    16     memset(lev,-1,sizeof(lev)); 
    17     int hd=0,tl=1;
    18     lev[s]=0; q[hd]=s; 
    19     while(hd<tl){ 
    20         int v=q[hd++];
    21         for(int i=head[v];i;i=e[i].next)
    22             if(e[i].cap>0&&lev[e[i].to]<0){ 
    23                 lev[e[i].to]=lev[v]+1;
    24                 q[tl++]=e[i].to;
    25             }
    26     }
    27     if(lev[t]==-1) return false;
    28     return true;
    29 } 
    30 int dfs(int u,int f){ 
    31     int used=0;
    32     if(u==t) return f;
    33     for(int i=head[u];i;i=e[i].next){
    34         if(e[i].cap>0&&lev[u]<lev[e[i].to]){
    35             int w=dfs(e[i].to,min(f-used,e[i].cap));
    36             if(w>0){
    37                 e[i].cap-=w; e[e[i].rev].cap+=w; used+=w; 
    38                 if(used==f) break; 
    39             }
    40         }
    41     }
    42     if(!used) lev[u]=-1;
    43     return used;
    44 }
    45 int dinic(){
    46     int flow=0;
    47     while(bfs()) flow+=dfs(s,INF);
    48     return flow;
    49 }
    50 bool check(int x,int y){return x>=1&&x<=n&&y>=1&&y<=m;}
    51 int main()
    52 {
    53     freopen("sacrifice.in","r",stdin);
    54     freopen("sacrifice.out","w",stdout);
    55     scanf("%d%d",&n,&m); s=0; t=n*m+1;
    56     for(int i=1;i<=n;i++)
    57         for(int j=1;j<=m;j++){
    58             int x; scanf("%d",&x);
    59             if(x<=0) continue;else sum+=x;
    60             if(i+j&1) ins(s,(i-1)*m+j,x);
    61             else ins((i-1)*m+j,t,x);
    62         }
    63     int ni,nj;
    64     for(int i=1;i<=n;i++)
    65         for(int j=1;j<=m;j++)
    66             if(i+j&1)for(int k=0;k<8;k++)
    67                 if(check(ni=i+dx[k],nj=j+dy[k]))
    68                     ins((i-1)*m+j,(ni-1)*m+nj,INF);
    69     printf("%d",sum-dinic());
    70     return 0;
    71 }

    操作声明:tp:枚举第i个点为终点时在起点等待的时间。x-i:竹笋长出来的时间-走到该点最少需要时间,即要采摘该点竹笋至少需要在起点等待的时间。

    题解:若知道我们知道终点,那么最优的情况就是在起点等待若干秒,最后不停地走到终点且到终点时时间刚好结束,所以我们就枚举终点啦。用一个堆维护最大值,一旦堆顶大于tp,则弹出,ans减去该点权值。若权值为负,直接踢掉即可。

    代码如下:

     1 #include<cstdio>
     2 #include<iostream>
     3 #include<queue>
     4 #define MN 500005
     5 using namespace std;
     6 int n,m,w[MN],tp;
     7 long long ans,mx;
     8 struct node{
     9     int pos,v;
    10     friend bool operator<(const node& a,const node& b){
    11         return a.pos<b.pos;
    12     }
    13 };
    14 priority_queue<node> q;
    15 int main()
    16 {
    17     freopen("urge.in","r",stdin);
    18     freopen("urge.out","w",stdout);
    19     scanf("%d%d",&n,&m); tp=m-1; 
    20     for(int i=1;i<=n;i++) scanf("%d",&w[i]);
    21     for(int i=1;i<=min(n,m-1);i++){
    22         tp--; int x;
    23         scanf("%d",&x); x-=i;
    24         while(!q.empty()&&q.top().pos>tp) ans-=q.top().v,q.pop();
    25         if(x<=tp&&w[i]>0) q.push((node){x,w[i]}),ans+=w[i];
    26         mx=max(mx,ans);
    27     }
    28     printf("%lld",mx);
    29     return 0;
    30 }
  • 相关阅读:
    第三章例3-3
    第三章例3-2
    第二章例2-11
    第二章例2-10
    第二章例2-9
    204
    205
    202
    203
    201
  • 原文地址:https://www.cnblogs.com/Beginner-/p/7592916.html
Copyright © 2020-2023  润新知