2018.10.5模拟赛

猫出的题···果然毒瘤

T1

猫说是送分题,好多人满分,多判了-1挂了10分···

改后代码:

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#define LL long long
using namespace std;
LL A,B,t,ans;

LL gcd(LL a,LL b){
	return b==0?a:gcd(b,a%b);
}

void solve(LL a,LL b){
	if(ans==-1) return;
	if(a==0 || b==0){
		return;
	} 
	if(b==1) {
		ans+=a; return;
	}
	if(a>b){
		ans+=a/b;
		solve(b,a%b);
	}
	else{
		ans+=b/a;
		solve(a,b%a);
	}
	
}

int main(){
	freopen("dragon.in","r",stdin);
	freopen("dragon.out","w",stdout);
	scanf("%lld%lld%lld",&A,&B,&t);
	if(A==0) return cout<<-1,0;
	solve(A,B);
	if(ans==-1) puts("-1");
	else printf("%lld\n",ans*t);
	return 0;
}

T2

模型抽象题?

可以把各种状态之间的关系看成一棵树,树根就是b-a=c-b

从根往子树走就相当于扩展,因为扩展两种一定都可以,而往父亲走就相当于收缩,因为一定只有一种方案

那么就可以看从一开始到最后恰好经过k个点的方案数

因为这是一颗无限满二叉树,所以从每个节点往下其实都是等价的

所以可以先处理出来起点状态和终点状态向上k步的情况

然后dfs往上往下跳再转移就好了

(以及注释是我自己的理解我也看不太懂std写的什么玩意 如果有错请指出)

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<vector>
#define maxn 105
#define LL long long
using namespace std;
int n,m,root=-1,str,f[maxn][maxn<<1][maxn<<1],k;
const int mod=1e9+7;
typedef vector<LL> Vec;
Vec c[maxn],d[maxn],now,pre,a,b;

Vec gether(Vec x){
	if(x[1]-x[0]==x[2]-x[1]) return x;
	Vec ret(3);
	if(x[1]-x[0]>x[2]-x[1])
		ret[0]=x[0],ret[1]=2*x[1]-x[2],ret[2]=x[1];
	else
		ret[0]=x[1],ret[1]=2*x[1]-x[0],ret[2]=x[2];
	return ret;
}

int dfs(int cur,int p,int q){//还有k步,到最高点还有p步,从lca到b还要q步 
	if(p<root || cur<0 || q<0) return 0;
	int &res=f[cur][p][q];
	if(res>=0) return res;
	res=0;
	if(p>q){
		(res+=dfs(cur-1,p-1,q))%=mod;
		(res+=dfs(cur-1,p+1,q)*2%mod)%=mod;//往下走,两个子树是等价的 
	}
	if(p==q){//走到了lca 
		(res+=dfs(cur-1,p-1,q-1))%=mod;
		(res+=dfs(cur-1,p+1,min(str-n+m,q+1)))%=mod;
		(res+=dfs(cur-1,p+1,q))%=mod;
	} return res;
}

int main(){
	freopen("rabbit.in","r",stdin);
	freopen("rabbit.out","w",stdout);
	LL A,B,C,D,E,F;
	cin>>A>>B>>C>>D>>E>>F>>k;
	a.push_back(A),a.push_back(B),a.push_back(C);
	b.push_back(D),b.push_back(E),b.push_back(F);
	sort(a.begin(),a.end()); sort(b.begin(),b.end());
	c[0]=a; d[0]=b;
	for(int i=1;i<=k;i++)
		c[i]=gether(c[i-1]),d[i]=gether(d[i-1]);
	for(n=0;n<=k;n++){
		for(m=0;m<=k;m++)
			if(c[n]==d[m]) break;
		if(c[n]==d[m]) break;
	}
	if(n+m>k) return cout<<0,0;//
	now=c[n],pre=now;
	for(int i=n+1;i<=k;i++){
		now=gether(now);
		if(now==pre) {
			root=i-n-1; break;//lca到根的距离 
		}
		pre=now;
	}
	if((n+m)%2!=k%2) return cout<<0,0;//
	memset(f,0xcf,sizeof f);
	str=(k-n-m)/2+n;//从a往上走到的最高处 
	if(root>=0) root=str-n-root;//从根往下走的最低处 
	else root=0;
	f[0][str-n+m][str-n+m]=1;//初始状态 
	cout<<dfs(k,str,str-n)<<endl;
	return 0; 
}

T3

一道暴力能拿92的题qwq但是我暴力好像挂了不少分

正解是分治,因为根据题的性质可以把点分成一排一排的

然后发现l~r中,可以去掉某些点让两部分变成独立的,这就是类似分治的本质qwq

虽然说spfa会死,但是这道题你可以只考虑l~r之中的,所以不会t掉

那个分治写起来还是挺复杂的···

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring> 
#include<cmath>
#include<queue>
#define N 50005
#define M 200005
#define LL long long
#define inf 0x3f3f3f3f
using namespace std;
int n,m,k,p,q,cnt,head[M];
int bel[M*10],tot;
int sum[M],c[M];
LL dis[M*10],ans[M];
bool vis[M*10];

struct EDGE{
	int to,w,nxt;
}edge[M<<1];

struct Query{
	int s,t,id;
}ask[M],t[M];

inline void add(int x,int y,int z){
	edge[++cnt].to=y; edge[cnt].nxt=head[x];
	edge[cnt].w=z; head[x]=cnt;
}

struct data{
	int v;
	bool operator <(const data &a) const{
		return dis[v]>dis[a.v];
	}
};
priority_queue <data> Q;

inline void spfa(int l,int r,int s){
	for(int i=sum[l-1]+1;i<=sum[r];i++)
		dis[i]=1LL<<60;
	vis[s]=1,dis[s]=0,Q.push((data){s});
	while(!Q.empty()){
		int u=Q.top().v; vis[u]=0; Q.pop();
		for(int i=head[u];i;i=edge[i].nxt){
			int v=edge[i].to;
			if(l>bel[v] || bel[v]>r) continue;
			if(dis[v]>dis[u]+edge[i].w){
				dis[v]=dis[u]+edge[i].w;
				if(!vis[v]) vis[v]=1,Q.push((data){v});
			}
		}
	}
}

void divide(int l,int r,int ql,int qr){
	if(ql>qr) return;
	if(r-l+1<=k+5){
		for(int i=ql;i<=qr;i++){
			spfa(l,r,ask[i].s);
			ans[ask[i].id]=min(ans[ask[i].id],dis[ask[i].t]);
		}return;
	}
	int ll=r+l-k>>1,rr=ll+k+1;
	int qll=ql,q1,q2;
	for(int i=ql;i<=qr;i++) t[i]=ask[i];
	for(int i=ql;i<=qr;i++)
		if(bel[t[i].s]<=ll && bel[t[i].t]<=ll) ask[qll++]=t[i];
	q1=qll-1;
	for(int i=ql;i<=qr;i++)
		if(bel[t[i].s]>=rr && bel[t[i].t]>=rr) ask[qll++]=t[i];
	q2=qll-1;
	for(int i=ql;i<=qr;i++)
		if(!(bel[t[i].s]<=ll&&bel[t[i].t]<=ll || bel[t[i].s]>=rr&&bel[t[i].t]>=rr))
			ask[qll++]=t[i];
	for(int i=sum[ll]+1;i<=sum[rr-1];i++){
		spfa(l,r,i);
		for(int j=ql;j<=qr;j++)
			ans[ask[j].id]=min(ans[ask[j].id],dis[ask[j].s]+dis[ask[j].t]);
	}
	divide(l,ll,ql,q1);
	divide(rr,r,q1+1,q2);
}

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

int main(){
	freopen("transport.in","r",stdin);
	freopen("transport.out","w",stdout); 
	n=rd(),m=rd(),k=rd(),p=rd(),q=rd();
	for(int i=1;i<=n;i++){
		c[i]=rd();
		for(int j=1;j<=c[i];j++) bel[++tot]=i;
		sum[i]=sum[i-1]+c[i];
	}
	memset(ans,0x3f,sizeof ans);
	for(int i=1;i<=m;i++){
		int x=rd(),y=rd(),z=rd();
		add(x,y,z); add(y,x,z);
	}
	for(int i=1;i<=q;i++){
		ask[i].s=rd(),ask[i].t=rd(); ask[i].id=i;
	}
	divide(1,n,1,q);
	for(int i=1;i<=q;i++){
		if(ans[i]>inf) puts("-1");
		else printf("%lld\n",ans[i]);
	} 
	return 0;
}
//5 11 1 2 5 
//2 2 2 2 2 
//1 2 1 
//1 3 2 
//2 3 1 
//3 4 1 
//3 5 2 
//4 5 1 
//5 6 1 
//5 7 2 
//6 7 1 
//7 8 1 
//9 10 1 
//1 4 
//2 8 
//5 7 
//9 4 
//3 2

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值