1. 程式人生 > >2018.10.11模擬賽

2018.10.11模擬賽

T1

一道類似貪心的模擬題,就是要刪除一些讓min{a}min{b}min\{a\}*min\{b\}最大

可以先存兩個結構體,一個按aa排序,一個按bb排序,然後列舉aa中刪掉幾個,看相應的bb中最多能刪掉幾個

首先aa裡刪掉00個的時候,bb中一定可以刪掉mm個,aa不斷往後刪除,如果它刪的那個矩形在bb中的位置在前mm個,那它就不用再在bb中刪除了,就這樣用兩個指標維護一下就好了

#include<iostream>
#include<cstdio>
#include<algorithm>
#include
<cstring>
#include<cmath> #define maxn 100005 #define LL long long #define inf 0x3f3f3f3f using namespace std; int t,n,m,pos[maxn],vis[maxn],cas; inline int rd(){ int x=0,f=1;char c=' '; while(c<'0' || c>'9') f=c=='-'?-1:1,c=getchar(); while(c<='9' && c>='0') x=x*10+c-'0',c=
getchar(); return x*f; } struct qwq{ int a,b,id; bool operator <(const qwq &x) const{ return a<x.a||(a==x.a&&b<x.b); } }tra[maxn],trb[maxn]; inline bool cmp(qwq x,qwq y){return x.b<y.b||(x.b==y.b&&x.a<y.a);} int main(){ freopen("d.in","r",stdin); freopen
("d.out","w",stdout); t=rd(); while(t--){ n=rd(); m=rd(); cas++; for(int i=1;i<=n;i++) tra[i].a=rd(),tra[i].b=rd(),tra[i].id=i, trb[i].a=tra[i].a,trb[i].b=tra[i].b,trb[i].id=i; sort(tra+1,tra+n+1); sort(trb+1,trb+n+1,cmp); for(int i=1;i<=n;i++) pos[trb[i].id]=i; int l=0,r=m+1,mna=0,mnb=0; LL ans=1LL*tra[1].a*trb[r].b; for(int i=1;i<=m;i++){ if(pos[tra[i].id]<r) vis[pos[tra[i].id]]=cas; else{ r--; while(vis[r]==cas) r--; } ans=max(ans,1LL*tra[i+1].a*trb[r].b); } printf("%lld\n",ans); } return 0; }

T2

這個題其實有很多種方法可以過掉,stdstd給的好像是狀壓dp+SPFAdp+SPFA,然後有人還用狀壓+dijkstra+dijkstra過掉

但是!我用的是優秀的dfsdfs!這真是暴力拍標算的例項啊

可以發現如果點度都是偶數那麼一定可以一遍走到,因此只要把所有度數為奇的點拿出來兩兩匹配,邊的長度就是他們的最短路,用之前所有的邊的長度加上最小的兩兩配對的邊長度就是答案

然後可以用各種各樣的姿勢和小剪枝來優化

實測比stdstd

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#define N 25
#define M 1005
#define inf 0x3f3f3f3f
using namespace std;
int n,m,ans,f[N][N],d[N];
int nw[N],tot,val[N][N],res=inf;
bool vis[N];

inline int rd(){
	int x=0,f=1;char c=' ';
	while(c<'0' || c>'9') f=c=='-'?-1:1,c=getchar();
	while(c<='9' && c>='0') x=x*10+c-'0',c=getchar();
	return x*f;
}

inline void dfs(int now,int sum,int t){
	if(t==tot/2){
		res=min(res,sum);
		return;
	}
	if(res<=sum) return;
	if(vis[now]) {
		dfs(now+1,sum,t); return;
	}
	vis[now]=1;
	for(int i=now+1;i<=tot;i++)
		if(!vis[i]){
			vis[i]=1;
			dfs(now+1,sum+val[now][i],t+1);
			vis[i]=0;
		}
	vis[now]=0;
	return;
}

int main(){
	freopen("jogging.in","r",stdin);
	freopen("jogging.out","w",stdout);
	n=rd(); m=rd(); memset(f,0x3f,sizeof f);
	for(int i=1;i<=m;i++){
		int x=rd(),y=rd(),z=rd(); d[x]++,d[y]++;
		ans+=z; f[x][y]=f[y][x]=min(f[x][y],z);
	}
	for(int i=1;i<=n;i++) f[i][i]=0;
	for(int k=1;k<=n;k++)
		for(int i=1;i<=n;i++)
			for(int j=1;j<=n;j++)
				f[i][j]=min(f[i][j],f[i][k]+f[k][j]);
	for(int i=1;i<=n;i++)
		if(d[i]&1)
			nw[++tot]=i;
	for(int i=1;i<=tot;i++)
		for(int j=i+1;j<=tot;j++)
			val[i][j]=val[j][i]=f[nw[i]][nw[j]];
	dfs(1,0,0);
	printf("%d\n",ans+res);
	return 0;
}
/*
4 6
1 2 3
2 3 4
3 4 5
1 4 10
1 3 12
2 4 8
*/ 

T3

毒瘤題···

題解說的很清晰了

TIM圖片20181012120057

具體實現看程式碼註釋吧,還是挺難寫的,綜合了trietrie樹,meetintthemiddlemeet\ int\ the\ middle,二分答案···

總之是一道考驗程式碼能力的好題咯

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<vector>
#define prit pair<LL,LL>
#define mp make_pair
#define fi first
#define se second
#define N 500005
#define K 35
#define M N*31
#define LL long long
using namespace std;
int n,k,a[N],trie[M][2],tot=1,siz[M];
LL val0[K],val1[K],p;
vector< prit > vec1,vec2;

inline int rd(){
	int x=0,f=1;char c=' ';
	while(c<'0' || c>'9') f=c=='-'?-1:1,c=getchar();
	while(c<='9' && c>='0') x=x*10+c-'0',c=getchar();
	return x*f;
}

inline void insert(int x){
	int now=1;
	for(int i=k-1;i>=0;i--){
		++siz[now]; 
		if((x>>i)&1)//這一位是1 
			val1[i]+=siz[trie[now][0]];
		else val0[i]+=siz[trie[now][1]];
		if(!trie[now][(x>>i)&1]) now=trie[now][(x>>i)&1]=++tot;
		else now=trie[now][(x>>i)&1];
	}
	++siz[now];
}

inline bool check(prit lim){
	LL res=0;//雙指標 
	for(int i=0,j=vec2.size()-1;i<vec1.size();i++){
		while(j>=0 && mp(vec1[i].fi+vec2[j].fi,vec1[i].se|vec2[j].se)>lim)
			j--;//將前一半和後一半合併 
		res+=j+1;
	}
	return res>=p;
}

signed main(){
	freopen("f.in","r",stdin);
	freopen("f.out","w",stdout);
	n=rd(); k=rd(); scanf("%lld",&p);
	for(int i=1;i<=n;i++){
		a[i]=rd(); insert(a[i]);//插入01trie 
	}
	int k1=k/2,k2=k-k1;//meet in the middle 
	for(int i=0;i<(1<<k1);i++){
		LL tmp=0;
		for(int j=0;j<k1;j++)
			if((i>>j)&1) tmp+=val1[j];
			else tmp+=val0[j];
		vec1.push_back(mp(tmp,i));
	}
	for(int i=0;i<(1<<k2);i++){
		LL tmp=0;
		for(int j=0;j<k2;j++)
			if((i>>j)&1) tmp+=val1[j+k1