17.10.20
- Time flies、、、
- 上午
- BOZJ 1057 [ZJOI2007]棋盘制作
神奇悬线大法好、、、
h[i][j]:(i,j)可以向上延伸多长
转移:h[i][j]=(j!=1&&(mp[i][j]^mp[i-1][j]))?h[i-1][j]+1:1
L[i][j]:(i,j)可以向左延伸多长
转移:L[i][j]=(j!=1&&(mp[i][j]^mp[i][j-1]))?L[i][j-1]+1:1
R[i][j]:(i,j)可以向右延伸多长
转移:R[i][j]=(j!=n&&(mp[i][j]^mp[i][j+1]))?R[i][j+1]+1:1
l[i][j]:以(i,j)为下底上的一点,h(i,j)为高的矩形可以向左延伸多长
转移:l[i][j]=(i!=1&&(mp[i][j]^mp[i-1][j]))?min(L[i][j],l[i-1][j]):L[i][j]
r[i][j]:以(i,j)为下底上的一点,h(i,j)为高的矩形可以向右延伸多长
转移:r[i][j]=(i!=1&&(mp[i][j]^mp[i-1][j]))?min(R[i][j],r[i-1][j]):R[i][j]
然后对于每个位置(i,j)
以它为下底上的一点,h(i,j)为高的矩形面积 = h[i][j]*(r[i][j]+l[i][j]-1)
至于正方形,面积 = min(h[i][j],r[i][j]+l[i][j]-1)*min(h[i][j],r[i][j]+l[i][j]-1)
(转移还是很清晰的,但这个方法真的很666)
代码:
#include<cstdio>
#include<cstring>
#include<iostream>
#define MAXN 2005
using namespace std;
int mp[MAXN][MAXN];
int h[MAXN][MAXN],l[MAXN][MAXN],r[MAXN][MAXN],L[MAXN][MAXN],R[MAXN][MAXN];
int n,m,ans1,ans2;
int main(){
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
scanf("%d",&mp[i][j]);
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++)
h[i][j]=(j!=1&&(mp[i][j]^mp[i-1][j]))?h[i-1][j]+1:1;
for(int j=1;j<=m;j++)
L[i][j]=(j!=1&&(mp[i][j]^mp[i][j-1]))?L[i][j-1]+1:1;
for(int j=m;j>=1;j--)
R[i][j]=(j!=n&&(mp[i][j]^mp[i][j+1]))?R[i][j+1]+1:1;
for(int j=1;j<=m;j++){
l[i][j]=(i!=1&&(mp[i][j]^mp[i-1][j]))?min(L[i][j],l[i-1][j]):L[i][j];
r[i][j]=(i!=1&&(mp[i][j]^mp[i-1][j]))?min(R[i][j],r[i-1][j]):R[i][j];
ans1=max(ans1,min(h[i][j],r[i][j]+l[i][j]-1)*min(h[i][j],r[i][j]+l[i][j]-1));
ans2=max(ans2,h[i][j]*(r[i][j]+l[i][j]-1));
}
}
printf("%d\n%d",ans1,ans2);
return 0;
}
- lence选讲
- 下午
- BZOJ 1058 [ZJOI2007]报表统计
stl大法好
第一个可重集维护序列相邻两个元素的差值,
插入元素时,先抹去插入位置的差值,在加入两个新的差值
第二个可重集维护所有的元素,加入一个新元素时就取出比它小的和比它大的那两个元素
,更新答案。
代码:
#include<set>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define INF 0x3f3f3f3f
#define MAXN 500005
#define siter set<int>::iterator
using namespace std;
multiset<int>s1,s2;
int Begin[MAXN],End[MAXN];
int ans1=INF,ans2=INF,n,m;
void Getans2(int x){
siter si=s2.find(x),sj;
if(si!=s2.begin()) sj=si,sj--,ans2=min(ans2,x-(*sj));
sj=si; sj++; if(sj!=s2.end()) ans2=min(ans2,*(sj)-x);
}
int main(){
char s[15]; int a,b,len;
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++) scanf("%d",&Begin[i]),End[i]=Begin[i];
for(int i=1;i<=n;i++){
if(i!=n) s1.insert(abs(Begin[i+1]-End[i]));
s2.insert(Begin[i]);
Getans2(Begin[i]);
}
for(int i=1;i<=m;i++){
scanf("%s",s); len=strlen(s);
if(len==6){
scanf("%d%d",&a,&b);
if(a!=n){
siter si=s1.find(abs(Begin[a+1]-End[a]));
s1.erase(si);
s1.insert(abs(Begin[a+1]-b));
}
s1.insert(abs(b-End[a])); End[a]=b;
s2.insert(b);
Getans2(b);
}
else if(len==7) {
ans1=*(s1.begin());
printf("%d\n",ans1);
}
else if(len==12)
printf("%d\n",ans2);
}
return 0;
}
- lence又来?!
- 晚上
- BZOJ 1059 [ZJOI2007]矩阵游戏
二分图匹配
对于一个黑点(i,j)
把点i向j+n连边,然后二分图匹配
如果是完美匹配的话,则合法
因为完美匹配选出来的那些点是行列各异的,一定可以调整到主对角线上去。
代码:
#include<cstdio>
#include<cstring>
#include<iostream>
using namespace std;
struct edge{
int to,next;
}e[200*200+50];
int vis[405];
int head[405],match[405];
int n,T,ent,cnt,tim;
void init(){
memset(head,0,sizeof(head));
memset(match,0,sizeof(match));
ent=2; cnt=0;
}
void add(int u,int v){
e[ent]=(edge){v,head[u]};
head[u]=ent++;
}
bool Find(int u){
for(int i=head[u];i;i=e[i].next){
int v=e[i].to;
if(vis[v]==tim) continue;
vis[v]=tim;
if(!match[v]||Find(match[v])){
match[v]=u;
return 1;
}
}
return 0;
}
int main(){
scanf("%d",&T);
while(T--){
init(); int x;
scanf("%d",&n);
for(int i=1;i<=n;i++)
for(int j=n+1;j<=2*n;j++){
scanf("%d",&x);
if(x) add(i,j);
}
for(int i=1;i<=n;i++){
tim++;
if(Find(i)) cnt++;
}
if(cnt==n) puts("Yes");
else puts("No");
}
return 0;
}
- BZOJ 1060 [ZJOI2007]时态同步
贪心吧。
最后大家都要达到的时间就是耗时最长的那个叶子的时间,因为增加最终时间的话代价只会更大。
计算出每个叶子需要延长的时间 ,
tim[i]表示i节点与fa[i]的边上预计增加的权值
显然 对于 u节点的所有儿子v
tim[u]=min(tim[v])
上式的意思是u的儿子都需要增加某一权值的话,那就直接加给u和fa[u]那条边上。
然后u的儿子v剩下的权值tim[v]-tim[u]就累计到ans,表示把剩下的权值放在v与u的那条边上。
由于s(起点)无fa,所以特别的tim[u]=0
代码:
#include<cstdio>
#include<cstring>
#include<iostream>
#define ll long long
#define INF 0x3f3f3f3f3f3f3f3f
#define MAXN 500005
using namespace std;
struct edge{
int to,val,next;
}e[MAXN*2];
int head[MAXN];
ll tim[MAXN],ans,maxtime;
int n,s,ent=2;
void read(int &x){
static int f; static char ch;
x=0; f=1; ch=getchar();
while(ch<'0'||'9'<ch){if(ch=='-') f=-1;ch=getchar();}
while('0'<=ch&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
x*=f;
}
void add(int u,int v,int w){
e[ent]=(edge){v,w,head[u]};
head[u]=ent++;
}
void dfs1(int u,int fa,ll t){
if(!e[head[u]].next) tim[u]=t,maxtime=max(maxtime,t); //叶子节点
for(int i=head[u];i;i=e[i].next){
int v=e[i].to;
if(v==fa) continue;
dfs1(v,u,t+e[i].val);
}
}
void dfs2(int u,int fa){
if(!e[head[u]].next) tim[u]=maxtime-tim[u]; //叶子节点
else tim[u]=(u==s)?0:INF; //非叶子节点
for(int i=head[u];i;i=e[i].next){
int v=e[i].to;
if(v==fa) continue;
dfs2(v,u);
tim[u]=min(tim[u],tim[v]);
}
for(int i=head[u];i;i=e[i].next){
int v=e[i].to;
if(v==fa) continue;
ans+=tim[v]-tim[u];
}
}
int main(){
read(n); read(s);
for(int i=1,a,b,c;i<n;i++)
read(a),read(b),read(c),add(a,b,c),add(b,a,c);
dfs1(s,0,0);
dfs2(s,0);
printf("%lld",ans);
return 0;
}
- BZOJ 1061 [Noi2008]志愿者招募
极好的题!!
让我对网络流建图产生了一点新的感觉
大佬详细题解,写得很好很详细,赞一个:
https://www.byvoid.com/zhs/blog/noi-2008-employee
代码:
#include<queue>
#include<cstdio>
#include<cstring>
#include<iostream>
#define INF 0x3f3f3f3f
using namespace std;
struct edge{
int to,capo,cost,next;
}e[30010];
int head[1010];
int n,m,ent=2,S,T;
void add(int u,int v,int capo,int cost){
e[ent]=(edge){v,capo,cost,head[u]};
head[u]=ent++;
e[ent]=(edge){u,0,-cost,head[v]};
head[v]=ent++;
}
void Readin_Build(){
scanf("%d%d",&n,&m);
S=n+2,T=n+3;
for(int i=1,last,now=0,w;i<=n+1;i++){
last=now; now=0;
if(i<=n) scanf("%d",&now);
w=now-last;
if(w>0) add(S,i,w,0);
else add(i,T,-w,0);
}
for(int i=1,l,r,w;i<=m;i++){
scanf("%d%d%d",&l,&r,&w);
add(l,r+1,INF,w);
}
for(int i=1;i<=n;i++)
add(i+1,i,INF,0);
}
bool spfa(int &Cost){
static bool inq[1010];
static int dis[1010],low[1010],p[1010];
queue<int>q;
memset(dis,0x3f,sizeof(dis));
q.push(S); inq[S]=1; dis[S]=0; low[S]=INF;
while(!q.empty()){
int u=q.front(); q.pop(); inq[u]=0;
for(int i=head[u];i;i=e[i].next){
if(!e[i].capo) continue;
int v=e[i].to;
if(dis[v]<=dis[u]+e[i].cost) continue;
dis[v]=dis[u]+e[i].cost;
low[v]=min(e[i].capo,low[u]);
p[v]=i;
if(!inq[v]) q.push(v),inq[v]=1;
}
}
if(dis[T]==INF) return 0;
Cost+=low[T]*dis[T];
int u=T;
while(u!=S){
e[p[u]].capo-=low[T];
e[p[u]^1].capo+=low[T];
u=e[p[u]^1].to;
}
return 1;
}
void Mincost_Maxflow(){
int Cost=0;
while(spfa(Cost));
printf("%d",Cost);
}
int main(){
Readin_Build();
Mincost_Maxflow();
return 0;
}
Do not go gentle into that good night.
Rage, rage against the dying of the light.
————Dylan Thomas

浙公网安备 33010602011771号