CQOI2016 day1 总结

怎么发一次格式抽一次

T1
打表发现答案小于n
考虑求出S,T的最小割,并且提取出在S这一边和在T这一边的点集
考虑S'属于S这一边的点集,T'属于T这一边的点集,那么S'和T'的最小割可以用其他两个点代替
借助bzoj2229黄学长的一句话:
注意这样一个事实:如果(X,Y)是某个s1-t1最小割,(Z,W)是某个s2-t2最小割,那么X∩Z、X∩W、Y∩Z、Y∩W这四项不可能均非空。也就是说,最小割不可能相互跨立。
这个蕴含了,最多一共有N-1个不同的s-t最小割。只需把这些割找出来即可。
寻找的方法:首先,在V中任意找两个点a,b,求最大流,把V划分为割X-Y,之后对X、Y分别递归地进行划分。这样就能得到N-1个割了。
那么我们可以分治求最小割,这样求得的最小割一定能够代表所有的最小割


T2
第一种:考场上YY出来的,因为太懒所以没写
首先求凸包,求出凸包上每一个点所能到达的最远点,push到堆中
对全局维护一个堆,每次弹出最大值,然后讲两个点的次远点在kd树中找出来
找出来的复杂度是sqrt(n)的,外加二份答案,共k次,总复杂度k*sqrt(n)*log(没有代码)
第二种
还是求出凸包和每一个点所能到达的最远点,每次拿出堆中的时候暴力扫n个点,强行插入次远的点
所以下面这个是nklog的。也能过


T3
傻逼数位dp
dp[当前位数][是否有8][是否有4][上一位][连续几位][已经有没有3位连续的][是否达到上限]
dfs一遍记忆化转移就好 
顺便说一句,函数记得return啊!!!关键是小数据还是对的调崩我了


代码

T1

//Copyright(c)2016 liuchenrui
#include<bits/stdc++.h>
#define short unsigned short
#define inf 1000000000
using namespace std;
template<typename T>
inline void splay(T &v){
	v=0;char c=0;T p=1;
	while(c<'0' || c>'9'){if(c=='-')p=-1;c=getchar();}
	while(c>='0' && c<='9'){v=(v<<3)+(v<<1)+c-'0';c=getchar();}
	v*=p;
}
struct Edge{
	short to,next;int flow;
}edge[100010];
short first[851],size;
short deep[851],dl[851];
void addedge(short x,short y,int z){
	size++;
	edge[size].to=y;
	edge[size].next=first[x];
	first[x]=size;
	edge[size].flow=z;
}
void add(short x,short y,int z){
	addedge(x,y,z),addedge(y,x,0);
}
short aim;
int dfs(short now,int flow){
	if(now==aim)return flow;
	int F=0;
	for(short u=first[now];u&&flow;u=edge[u].next){
		if(deep[edge[u].to]==deep[now]+1&&edge[u].flow){
			int tmp=dfs(edge[u].to,min(flow,edge[u].flow));
			F+=tmp;edge[u].flow-=tmp;edge[u^1].flow+=tmp;flow-=tmp;
		}
	}
	if(!F)deep[now]=-5;
	return F;
}
bool bfs(short S,short T){
	memset(deep,0,sizeof(deep));
	dl[1]=S;deep[S]=1;
	short head=0,tail=1;
	while(head!=tail){
		head++;
		for(int u=first[dl[head]];u;u=edge[u].next){
			if(!deep[edge[u].to]&&edge[u].flow){
				dl[++tail]=edge[u].to;
				deep[edge[u].to]=deep[dl[head]]+1;
			}
		}
	}
	return deep[T];
}
int maxflow(short S,short T){
	int ret=0;aim=T;
	while(bfs(S,T)){
		ret+=dfs(S,inf);
	}
	return ret;
}
short fr[8600],to[8600];
int fl[8600];
int ans[1000010];
short cnt,n,m,p[851];
void rebuild(){
	memset(first,0,sizeof first);
	size=1;
	for(int k=1;k<=m;k++){
		add(fr[k],to[k],fl[k]);
		add(to[k],fr[k],fl[k]);
	}
}
bool vis[860];
void dfs2(short now){
	vis[now]=1;
	for(int u=first[now];u;u=edge[u].next){
		if(edge[u].flow&&!vis[edge[u].to]){
			dfs2(edge[u].to);
		}
	}
}
void cdq_calc(short l,short r){
	if(l>=r)return;
	rebuild();
	ans[++cnt]=maxflow(p[l],p[r]);
	memset(vis,0,sizeof vis);
	dfs2(p[l]);int t=l-1;
	for(short i=l;i<=r;i++){
		if(vis[p[i]]){
			swap(p[i],p[++t]);
		}
	}
	cdq_calc(l,t),cdq_calc(t+1,r);
}
int main(){
	freopen("cuts.in","r",stdin);
	freopen("cuts.out","w",stdout);
	splay(n),splay(m);
	for(short i=1;i<=m;i++){
		splay(fr[i]),splay(to[i]),splay(fl[i]);
	}
	for(short i=1;i<=n;i++){
		p[i]=i;
	}
	cdq_calc(1,n);
	sort(ans+1,ans+cnt+1);
	cnt=unique(ans+1,ans+cnt+1)-ans-1;
	printf("%d\n",cnt);
	//cerr<<clock()<<endl;
}
T2是czh的代码,自己的WA没调出来

#include <iostream>
#include <cstring>
#include <cstdlib>
#include <string>
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <ctime>
#include <map>
#define inf (((unsigned long long)1 << (unsigned long long)63) - (unsigned long long)1)
#define Int long long
using namespace std;
struct point {Int x;Int y;int id;
};point p[100010],q[100010],stack[200010];
Int val[800010],minx[850],maxx[850];
int E,belong[100010],cnt,n,k;
int head,tail,father[100010],t,num[100010];
int tot[850];
map < pair<int,int>,int> mp;
Int calc(point x,point y,point z) {
	point A,B;
	A.x = x.x - z.x;
	A.y = x.y - z.y;
	B.x = y.x - z.x;
	B.y = y.y - z.y;
	return A.x * B.y - A.y * B.x;
}
Int dis(point x,point y) {
	Int ret = (x.x - y.x) * (x.x - y.x) + (x.y - y.y) * (x.y - y.y);
	return ret;
}
bool comp(const point &x,const point &y) {
	Int v = calc(x,y,p[1]);
	if(v == 0) return dis(x,p[1]) < dis(y,p[1]);
	return v > 0;
}
void build(int Now,int l,int r) {
	val[Now] = -1;
	if(l == r) return;
	int Mid = (l + r) >> 1;
	build(Now << 1,l,Mid);
	build(Now << 1 | 1,Mid + 1,r);
}
void change(int Now,int l,int r,int x,Int y) {
	if(l == r) {val[Now] = y;return ;}
	int Mid = (l + r) >> 1;
	if(x <= Mid) change(Now << 1,l,Mid,x,y);
	else change(Now << 1 | 1,Mid + 1,r,x,y);
	if(val[Now << 1] > val[Now << 1 | 1])
		val[Now] = val[Now << 1];
	else val[Now] = val[Now << 1 | 1];
}
int Ask(int Now,int l,int r) {
	if(l == r) return r;
	int Mid = (l + r) >> 1;
	if(val[Now << 1] == val[Now])
		return Ask(Now << 1,l,Mid);
	else return Ask(Now << 1 | 1,Mid + 1,r);
}
int find(int Now,int l,int r) {
	if(l == r) return r;
	int Mid = (l + r) >> 1;
	if(minx[Now] == minx[Now << 1])
		return find(Now << 1,l,Mid);
	else return find(Now << 1 | 1,Mid + 1,r);
}
void insert(int Now,int l,int r,int x,Int y) {
	if(l == r) {minx[Now] = maxx[Now] = y;tot[Now] = 1;return ;}
	int Mid = (l + r) >> 1;
	if(x <= Mid) insert(Now << 1,l,Mid,x,y);
	else insert(Now << 1 | 1,Mid + 1,r,x,y);
	tot[Now] = tot[Now << 1] + tot[Now << 1 | 1];
	minx[Now] = min(minx[Now << 1],minx[Now << 1 | 1]);
	maxx[Now] = max(maxx[Now << 1],maxx[Now << 1 | 1]);
}
int bf(int x) {
	int Z = num[x] + 1;
	for(int i = 1;i <= 810;i ++)
		minx[i] = inf,maxx[i] = -1,tot[i] = 0;
	for(int i = 1;i <= n;i ++)
	{
		Int G = dis(q[i],q[x]);
		if(tot[1] < Z)
			insert(1,1,100,tot[1] + 1,G);
		else if(minx[1] < G) 
			insert(1,1,100,find(1,1,100),G);
	}
	for(int i = 1;i <= n;i ++)
		if(dis(q[i],q[x]) == minx[1] && mp[make_pair(x,i)] == 0)
			return i;			
}
int getint() {
	char c = 'd';
	int ret = 0;
	while(c < '0' || c > '9') c = getchar();
	while(c >= '0' && c <= '9') ret = ret * 10 + c - '0',c = getchar();
	return ret;
}
int main() {
	freopen("farthest.in","r",stdin);
	freopen("farthest.out","w",stdout);
	n = getint();
	k = getint();
	for(int i = 1;i <= n;i ++)
		p[i].x = getint(),p[i].y = getint(),q[i].x = p[i].x,q[i].y = p[i].y,p[i].id = i;
	t = 1;
	for(int i = 2;i <= n;i ++)
		if(p[i].y < p[t].y || (p[i].y == p[t].y && p[i].x < p[t].x))
			t = i;
	swap(p[1],p[t]);
	sort(p + 2,p + n + 1,comp);
	head = 1;tail = 0;
	for(int i = 1;i <= n;i ++) 
	{
		while(head < tail && calc(p[i],stack[tail],stack[tail - 1]) > 0)
			tail --;
		stack[ ++ tail] = p[i];
	}
	for(int i = 1;i <= tail;i ++)
		stack[i + tail] = stack[i];
	int M = 1;
	build(1,1,n);
	for(int i = 1;i <= tail;i ++)
	{
		while(M < 2 * tail && dis(stack[M + 1],stack[i]) > dis(stack[M],stack[i]))
			M = M + 1;
		change(1,1,n,stack[i].id,dis(stack[i],stack[M]));father[stack[i].id] = stack[M].id;
	}
	for(int i = 1;i < k;i ++) 
	{
		int t = Ask(1,1,n),w = father[t];
		mp[make_pair(w,t)] = mp[make_pair(t,w)] = 1;
		num[t] ++;
		num[w] ++;
		father[t] = bf(t);
		father[w] = bf(w);
		change(1,1,n,t,dis(q[t],q[father[t]]));
		change(1,1,n,w,dis(q[w],q[father[w]]));
	}
	cout<<val[1];
}

T3

//Copyright(c)2016 liuchenrui
#include<bits/stdc++.h>
#define LL long long
using namespace std;
inline void splay(int &v){
	v=0;char c=0;int p=1;
	while(c<'0' || c>'9'){if(c=='-')p=-1;c=getchar();}
	while(c>='0' && c<='9'){v=(v<<3)+(v<<1)+c-'0';c=getchar();}
	v*=p;
}
int s[15];
LL dp[13][2][2][10][12][2][10];//当前位数,是否有8,是否有4,上一位,连续几位,已经有没有3位连续的,是否达到上限 
LL dfs(int a,int b,int c,int d,int e,int f,int g){
	if(a>11){
		if(b&&c)return 0;
		if(!f)return 0;
		return 1;
	}
	if(dp[a][b][c][d][e][f][g]!=-1)return dp[a][b][c][d][e][f][g];
	LL ret=0;int t;
	if(g==0){
		for(int i=0;i<=9;i++){
			if(i==d)t=e+1;else t=1;
			ret+=dfs(a+1,(b|(i==8)),(c|(i==4)),i,t,(t>=3)|(f),0);
		}
	}
	else{
		for(int i=0;i<s[a];i++){
			if(i==d)t=e+1;else t=1;
			ret+=dfs(a+1,(b|(i==8)),(c|(i==4)),i,t,(t>=3)|(f),0);
		}
		if(s[a]==d)t=e+1;else t=1;
		ret+=dfs(a+1,(b|(s[a]==8)),(c|(s[a]==4)),s[a],t,(t>=3)|(f),1);
	}
	return dp[a][b][c][d][e][f][g]=ret;
}
LL calc(LL a){
	if(a<10000000000LL)return 0;
	for(int i=11;i>=1;i--){
		s[i]=a%10;a/=10;
	}
	memset(dp,-1,sizeof dp);
	LL ret=0;
	for(int i=1;i<s[1];i++){
		ret+=dfs(2,i==8,i==4,i,1,0,0);
	}
	ret+=dfs(2,s[1]==8,s[1]==4,s[1],1,0,1);
	return ret;//nmb 记得return啊卧槽!!!!!!! 
}
int main(){
	freopen("number.in","r",stdin);
	freopen("number.out","w",stdout);
	LL x,y;
	cin>>x>>y;
	LL a=calc(x-1);
	LL b=calc(y);
	cout<<b-a<<endl;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值