10.11考试反思
10.11
Contest2141 - 2019年10月多校联训B层测试10
T1 劳作
http://www.accoders.com/problem.php?cid=2141&pid=0 题目传送门
T1 搜索 (for循环裸题) 每次输入的时候,记一下行和列出现的*次数以及总共的次数,然后枚举横行纵列就可以了,遇到一个可以的位置直接输出 return 就可以了
#include <bits/stdc++.h> #define ll long long #define res register #define MAXN 100050 #define int ll using namespace std; int n,m,cnt,h[MAXN],stx,sty,sum,q[MAXN]; char a; bool ju[3050][3050]; ll read() { int s=0,w=1;char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();} while(ch>='0'&&ch<='9'){s=(s<<1)+(s<<3)+ch-48;ch=getchar();} return s*w; } #undef int int main() { #define int ll n=read(),m=read(); for(res int i=1;i<=n;i++) for(res int j=1;j<=m;j++){ cin>>a; if(a=='*') ju[i][j]=1,h[i]++,q[j]++,sum++; } for(res int i=1;i<=n;i++) for(res int j=1;j<=m;j++){ if(h[i]+q[j]-ju[i][j]==sum) { cout<<"YES"<<endl; cout<<i<<" "<<j<<endl; return 0; } } cout<<"NO"<<endl; return 0; }
T2 浇水
http://www.accoders.com/problem.php?cid=2141&pid=1
T2是真的搜索 我们需要dfs2次,第一次求出来所有的湖泊数目,以及起点的横纵坐标存到结构体里,然后贪心,sort一下,填前k小的,然后输出就可以了
#include <bits/stdc++.h> #define MAXN 100050 #define res register #define db double #define int ll #define standard 1e-5 #define ll long long using namespace std; int n,m,dx[4]={0,1,0,-1},dy[4]={-1,0,1,0},ans,b[MAXN],k,tot,cnt,sum; char wa[1050][1050]; bool vis[1050][1050],ju; struct Node{ int ans,x,y; friend inline bool operator<(Node a,Node b){ return a.ans>b.ans; } }a[MAXN]; inline void dfs(int x,int y){ if(x==1||y==1||x==n||y==m) ju=0; vis[x][y]=1,tot++; for(res int i=0;i<4;i++){ int xx=x+dx[i],yy=y+dy[i]; if(xx>=1&&yy>=1&&xx<=n&&yy<=m&&!vis[xx][yy]&&wa[xx][yy]=='.') dfs(xx,yy); } } inline void dfs2(int x,int y){ wa[x][y]='*'; for(int i=0;i<4;i++){ int xx=x+dx[i],yy=y+dy[i]; if(wa[xx][yy]=='.') dfs2(xx,yy); } } ll read() { int s=0,w=1;char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();} while(ch>='0'&&ch<='9'){s=(s<<1)+(s<<3)+ch-48;ch=getchar();} return s*w; } signed main() { n=read(),m=read(),k=read(); for(res int i=1;i<=n;i++) for(res int j=1;j<=m;j++) cin>>wa[i][j]; for(res int i=1;i<=n;i++) for(res int j=1;j<=m;j++){ if(!vis[i][j]&&wa[i][j]=='.'){ ju=1;tot=0; dfs(i,j);if(ju){ a[++cnt].x=i,a[cnt].y=j;a[cnt].ans=tot; } } } sort(a+1,a+1+cnt); for(res int i=cnt;i>k;i--) sum+=a[i].ans,dfs2(a[i].x,a[i].y); cout<<sum<<endl; for(res int i=1;i<=n;i++){ for(res int j=1;j<=m;j++) cout<<wa[i][j]; cout<<endl; } return 0; }
T3 买菜
http://www.accoders.com/problem.php?cid=2141&pid=2
一道比较有难度的题,首先对于题意,我们需要求你所选择的蔬菜所构成的这个图的最大团,也就是求补图的最大独立集,我们建立补图的时候是个二分图,除了1,1连边之外就是奇数偶数连边,所以构成了二分图,考虑求二分图的最大匹配,匈牙利,但是显然这道题有点权,匈牙利算法不可解,我们换一种方法,很显然,dinic就可以解决了。我们考虑二分查找答案,用Dinic作check即可
1 #include <bits/stdc++.h> 2 #define MAXN 120 3 #define res register 4 #define inf 0x3f3f3f3f 5 #define db double 6 #define int ll 7 #define standard 1e-5 8 #define ll long long 9 using namespace std; 10 struct Edge{ 11 int to,nxt,dis; 12 }g[30050]; 13 struct Node{ 14 int p,c,l; 15 }a[MAXN]; 16 bool np[300050]={1,1}; 17 int n,m,k,head[MAXN],ss,tt,top,dis[MAXN]; 18 inline void add(int u,int v,int dis){ 19 g[++top].to=v,g[top].nxt=head[u]; 20 g[top].dis=dis;head[u]=top; 21 g[++top].to=u;g[top].nxt=head[v]; 22 g[top].dis=0;head[v]=top; 23 } 24 bool vis[MAXN]; 25 inline bool bfs(){ 26 memset(dis,0,sizeof(dis)); 27 memset(vis,0,sizeof(vis)); 28 queue<int>q; 29 vis[ss]=1;q.push(ss); 30 while(!q.empty()){ 31 int u=q.front();q.pop(); 32 for(int i=head[u];~i;i=g[i].nxt){ 33 int v=g[i].to; 34 if(g[i].dis&&!vis[v]){ 35 q.push(v);vis[v]=1; 36 dis[v]=dis[u]+1; 37 } 38 } 39 } 40 return vis[tt]; 41 } 42 inline int dfs(int u,int fa){ 43 if(u==tt) return fa; 44 int qwq=0; 45 for(int i=head[u];fa&&~i;i=g[i].nxt){ 46 int v=g[i].to; 47 if(g[i].dis&&dis[v]==dis[u]+1){ 48 int flow=dfs(v,min(g[i].dis,fa)); 49 g[i].dis-=flow; 50 g[i^1].dis+=flow; 51 fa-=flow; 52 qwq+=flow; 53 } 54 } 55 return qwq; 56 } 57 inline int dinic(){ 58 int qwq=0;while(bfs()) qwq+=dfs(ss,inf); 59 return qwq; 60 } 61 inline bool check(int x){ 62 top=-1;memset(head,-1,sizeof(head)); 63 int m=-1,w=-1; 64 for(res int i=1;i<=n;i++) 65 if(a[i].l<=x) if(a[i].c==1&&a[i].p>m) m=a[i].p,w=i; 66 int ans=0; 67 for(res int i=1;i<=n;i++) 68 if(a[i].l<=x){ 69 if(a[i].c==1&&i!=w) continue; 70 ans+=a[i].p; 71 if(a[i].c&1){ 72 add(ss,i,a[i].p); 73 for(res int j=1;j<=n;j++) 74 if(a[j].l<=x&&(~a[j].c&1)&&!np[a[i].c+a[j].c]) 75 add(i,j,inf); 76 } 77 else add(i,tt,a[i].p); 78 } 79 ans-=dinic(); 80 return ans<k; 81 } 82 inline int erfen(int l,int r){ 83 if(l==r) return l; 84 int mid=l+r>>1;if(!check(mid)) erfen(l,mid); 85 else erfen(mid+1,r); 86 } 87 ll read() 88 { 89 int s=0,w=1;char ch=getchar(); 90 while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();} 91 while(ch>='0'&&ch<='9'){s=(s<<1)+(s<<3)+ch-48;ch=getchar();} 92 return s*w; 93 } 94 inline void Init(){ 95 for(int i=2;i<=200000;++i)if(!np[i]) 96 for(int j=i*2;j<=200000;j+=i) np[j]=1; 97 } 98 signed main() 99 { 100 n=read(),k=read();Init();ss=n+1,tt=n+2; 101 for(res int i=1;i<=n;i++) a[i].p=read(),a[i].c=read(),a[i].l=read(); 102 cout<<erfen(1,n+1)<<endl; 103 return 0; 104 }
总结 这道题难点在于如何快速的把这个问题转化到网络流及二分图上,难点在于建立模型