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 }

 

posted @ 2017-09-25 17:25  Beginner_llg  阅读(209)  评论(1编辑  收藏  举报