修仙录 3.30

妙啊


jzoj 6091 唐时月夜

https://jzoj.net/senior/#main/show/6091
因为下一次的操作一定会包含以前操作过的范围
如果我们倒着处理每个变换显然是可以得到最终答案的
矩阵竟然有个什么线性变换。
玄学
反正就是维护坐标的变换系数,一次变化就直接在系数上改就行了。
那个莫名其妙的取模直接用unsigned int就好啦

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<algorithm>
#define LL unsigned int
using namespace std;
const int MAXN=4e3+5;
const int MAXM=2e5+5;
const LL mod=4294967296;

int num,n,m,q,op,l1,l2,r1,r2;
LL a,b,c,A[MAXN][MAXN],B[MAXN][MAXN],f[MAXN*MAXN],ans;
struct query{
	int op,l1,l2,r1,r2;
}qry[MAXM];
struct node{
	int x,y,l;
	node(){x=y=l=0;}
	node(int x,int y,int l):x(x),y(y),l(l){}
}X[MAXM],Y[MAXM];

void rev_1(node &a,node &b,int id){
	int v=qry[id].l2+qry[id].r2;
	a.l+=a.y*v,b.l+=b.y*v;
	a.y*=-1,b.y*=-1;
}

void rev_2(node &a,node &b,int id){
	int v=qry[id].l1+qry[id].r1;
	a.l+=a.x*v,b.l+=b.x*v;
	a.x*=-1,b.x*=-1;
}

void rev_3(node &a,node &b,int id){
	int v=qry[id].l1-qry[id].l2;
	a.l+=(a.x-a.y)*v,b.l+=(b.x-b.y)*v;
	swap(a.x,a.y),swap(b.x,b.y);
}

void solve(){
	node x=node(1,0,0),y=node(0,1,0);
	for(int i=q;i>=1;i--){
		if(qry[i].op==1) rev_1(x,y,i);
		if(qry[i].op==2) rev_2(x,y,i);
		if(qry[i].op==3) rev_3(x,y,i);
		X[i]=x,Y[i]=y;
	}
	for(int id=1;id<=q;id++)
		for(int i=qry[id].l1;i<=qry[id].r1;i++)for(int j=qry[id].l2;j<=qry[id].r2;j++)
			if(id>1&&qry[id-1].l1<=i&&i<=qry[id-1].r1&&j==qry[id-1].l2) j=qry[id-1].r2;
			else B[X[id].x*i+X[id].y*j+X[id].l][Y[id].x*i+Y[id].y*j+Y[id].l]=A[i][j];
}

int main(){
	freopen("evernight.in","r",stdin);
	freopen("evernight.out","w",stdout);
	cin>>num>>n>>m>>q>>a>>b>>c;f[0]=c;
	for(int i=1;i<=n*m;i++) f[i]=f[i-1]*a+b;
	for(int i=1;i<=n;i++)for(int j=1;j<=m;j++) B[i][j]=A[i][j]=f[(i-1)*m+j];
	for(int i=1;i<=q;i++) scanf("%d%d%d%d%d",&qry[i].op,&qry[i].l1,&qry[i].l2,&qry[i].r1,&qry[i].r2);
	solve();
	for(int i=1;i<=n;i++)for(int j=1;j<=m;j++) ans+=B[i][j]*f[(i-1)*m+j];
	cout<<ans;
	return 0;
}

jzoj 6092 附耳而至

https://jzoj.net/senior/#contest/show/2686/1
竟然又是网络流。
先极角排序+跑环找出所有的区域
变成对偶图(区域变成点,相邻有连边)
S向区域连光明值的边
区域向T连黑暗值的边
相邻的区域连代价的双向边
最小割表示不选的最小值
总和减去不选的就是答案

dinic要用当前弧优化

数组开小竟然是TLE,坑死我了

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<vector>
using namespace std;
const int MAXN=4e4+5;
const int MAXM=2e5+5;
const int inf=1e9;

void read(int &x){
	char c=getchar();
	int f=1; x=0;
	while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
	while(c>='0'&&c<='9') x=x*10+c-'0',c=getchar();
	x*=f;
}

int num,n,m,cnt=1,S,T,ans;
struct point{
	int x,y,a,b;
}p[MAXN];
struct edge{
	int v,c;
	double k;
	edge(){v=c=k=0;}
	edge(int u,int v,int c):v(v),c(c){k=atan2(p[v].y-p[u].y,p[v].x-p[u].x);}
	bool operator <(edge a){return k<a.k;}
}e[MAXM*2];

vector<int>g[MAXN];
void add(int u,int v,int c){
	e[++cnt]=edge(u,v,c),g[u].push_back(cnt);
	e[++cnt]=edge(v,u,c),g[v].push_back(cnt);
}

bool comp(int a,int b){return e[a]<e[b];}

struct graph{
	int head[MAXN*2],next[MAXN*10],to[MAXN*10],w[MAXN*10],cnt;
	int d[MAXN*2],q[MAXN*2],h,t,cur[MAXN*2];
	void init(){cnt=1;}
	void add(int u,int v,int c){
		next[++cnt]=head[u],to[cnt]=v,w[cnt]=c,head[u]=cnt;
		next[++cnt]=head[v],to[cnt]=u,w[cnt]=0,head[v]=cnt;
	}
	bool bfs(){
		memset(d,0,sizeof(d));
		d[S]=1,h=t=0;q[t++]=S;
		while(h<t){
			int x=q[h++];
			if(x==T) return 1;
			for(int i=head[x];i;i=next[i]){
				int y=to[i];
				if(!d[y]&&w[i]) d[y]=d[x]+1,q[t++]=y;
			}
		}
		return d[T];
	}
	int dfs(int x,int now){
		if(x==T) return now;
		int flow=0;
		for(int &i=cur[x];i;i=next[i]){
			int y=to[i];
			if(d[y]==d[x]+1&&w[i]){
				int can=dfs(y,min(now,w[i]));
				now-=can,flow+=can;
				w[i]-=can,w[i^1]+=can;
				if(!now) break;
			}
		}
		if(!flow) d[x]=-1;
		return flow;
	}
	int dinic(){
		int ans=0;
		while(bfs()) memcpy(cur,head,sizeof(head)),ans+=dfs(S,inf);
		return ans;
	}
}G;

vector<int>::iterator it;
int next[MAXM*2],isv[MAXM*2],tot,bl[MAXM*2],val1[MAXM*2],val2[MAXM*2];
void build(){
	for(int i=1;i<=n;i++) sort(g[i].begin(),g[i].end(),comp);
	for(int i=2;i<=cnt;i++){
		int v=e[i].v;
		it=++lower_bound(g[v].begin(),g[v].end(),i^1,comp);
		if(it==g[v].end()) it=g[v].begin();
		next[i]=*it;
	}
	for(int i=2;i<=cnt;i++)if(!isv[i]){
		tot++;
		for(int j=i;!isv[j];j=next[j]) isv[j]=1,bl[j]=tot;
	}
	G.init();
	for(int i=2,u,v,c;i<=cnt;i++){
		u=bl[i],v=bl[i^1],c=e[i].c;
		val1[u]+=p[e[i].v].a,val2[u]+=p[e[i].v].b;
		if(u>v) continue;
		G.add(u,v,c),G.add(v,u,c);
	}
	S=0,T=tot+1;
	for(int i=1;i<=tot;i++) G.add(S,i,val1[i]),G.add(i,T,val2[i]);
}

int main(){
	freopen("everfeel.in","r",stdin);
	freopen("everfeel.out","w",stdout);
	read(num),read(n),read(m);
	for(int i=1;i<=n;i++) read(p[i].x),read(p[i].y),read(p[i].a),read(p[i].b);
	for(int i=1,u,v,c;i<=m;i++) read(u),read(v),read(c),add(u,v,c);
	build();
	for(int i=1;i<=tot;i++) ans+=val1[i]+val2[i];
	cout<<ans-G.dinic();
	return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值