2019-10-5 NOIP模擬賽多校聯考——Round7 題解

T1 整數分解

裸的完全揹包……被孫到
2i2^i當作物品,容量爲nn

#include<stdio.h>
#include<cstring>
#include<algorithm>
#include<math.h>
#define re register int
#define mod 1000000007
using namespace std;
typedef long long ll;
int read() {
	re x=0,f=1;
	char ch=getchar();
	while(ch<'0' || ch>'9') {
		if(ch=='-')	f=-1;
		ch=getchar();
	}
	while(ch>='0' && ch<='9') {
		x=10*x+ch-'0';
		ch=getchar();
	}
	return x*f;
}
const int Size=1000005;
int n,dp[Size],LOG[Size];
int main() {
//	freopen("T1.in","r",stdin);
	n=read();
	dp[0]=1;
	for(re i=0; i<=20; i++) {
		for(re j=0; j+(1<<i)<=n; j++) {
			dp[j+(1<<i)]=(dp[j+(1<<i)]+dp[j])%mod;
		}
	}
	printf("%d",dp[n]);
	return 0;
}

T2 貧富差距
u,vu,v是朋友就建一條u,vu,v的邊。
如果所有的點都在同一個聯通塊中,那麼貧富差距的最大值就是最長鏈的長度乘以dd(易證無法構造出更大的貧富差距)。
判-1用並查集,判是否所有的點在同一個聯通塊中即珂,如果有兩個點不在同一個聯通塊中,則這兩個點的貧富差距珂以無限擴大。

#include<stdio.h>
#include<cstring>
#include<algorithm>
#include<math.h>
#define re register int
#define mod 1000000007
using namespace std;
int read() {
	re x=0,f=1;
	char ch=getchar();
	while(ch<'0' || ch>'9') {
		if(ch=='-')	f=-1;
		ch=getchar();
	}
	while(ch>='0' && ch<='9') {
		x=10*x+ch-'0';
		ch=getchar();
	}
	return x*f;
}
inline char GetChar() {
	char ch=getchar();
	while(ch!='Y' && ch!='N')	ch=getchar();
	return ch;
}
const int Size=105;
int n,d,father[Size];
int Find(int x) {
	if(x==father[x])	return x;
	return father[x]=Find(father[x]);
}
int cnt,head[Size];
struct node {
	int v,next;
} w[Size*Size<<1];
inline void AddEdge(int u,int v) {
	w[++cnt].v=v;
	w[cnt].next=head[u];
	head[u]=cnt;
}
int Queue[Size],dis[Size];
bool vis[Size];
int bfs(int s) {
	memset(vis,0,sizeof(vis));
	int hd=0,tl=0;
	Queue[++tl]=s;
	vis[s]=true;
	dis[s]=0;
	int ans=0;
	while(hd<tl) {
		int x=Queue[++hd];
		for(re i=head[x]; i; i=w[i].next) {
			int nxt=w[i].v;
			if(!vis[nxt]) {
				vis[nxt]=true;
				Queue[++tl]=nxt;
				dis[tl]=dis[hd]+1;
				if(dis[tl]>ans) {
					ans=dis[tl];
				}
			}
		}
	}
	return ans;
}
inline void init() {
	memset(head,0,sizeof(head));
	cnt=0;
	for(re i=1; i<=n; i++) {
		father[i]=i;
	}
}
int main() {
//	freopen("T2.in","r",stdin);
	int T=read();
	while(T--) {
		n=read();
		d=read();
		init();
		for(re i=1; i<=n; i++) {
			for(re j=1; j<=n; j++) {
				char ch=GetChar();
				if(ch=='Y') {
					AddEdge(i,j);
					int fx=Find(i);
					int fy=Find(j);
					if(fx!=fy) {
						father[fx]=fy;
					}
				}
			}
		}
		int fa=Find(1);
		bool inf=false;
		for(re i=2; i<=n; i++) {
			if(Find(i)!=fa) {
				inf=true;
				break;
			}
		}
		if(inf) {
			puts("-1");
			continue;
		}
		int ans=0;
		for(re i=1; i<=n; i++) {
			int now=bfs(i);
			if(now>ans) {
				ans=now;
			}
		}
		printf("%d\n",ans*d);
	}
	return 0;
}

T3 特殊的排列
找出序列上相鄰兩項差爲1的最長子序列,則這個子序列長度是最長的不用移動的長度。
證明:
1.移動一個子序列之外的數,子序列的相對順序不變。
2.不在最長子序列中的數一定要移動到序列首或序列末(否則珂以形成更長的相鄰兩項差爲1的子序列)。
3.不存在另一個更長的子序列,相鄰兩項差不爲1,且這個子序列中的數不用移動。因爲若相鄰兩項差不爲1,那麼這兩項之間的數必須要通過移動子序列裏的數來得到。

#include<stdio.h>
#include<cstring>
#include<algorithm>
#include<math.h>
#define re register int
using namespace std;
int read() {
	re x=0,f=1;
	char ch=getchar();
	while(ch<'0' || ch>'9') {
		if(ch=='-')	f=-1;
		ch=getchar();
	}
	while(ch>='0' && ch<='9') {
		x=(x<<1)+(x<<3)+ch-'0';
		ch=getchar();
	}
	return x*f;
}
const int Size=50005;
int dp[Size];
int main() {
	int n=read();
	int ans=0;
	for(re i=1; i<=n; i++) {
		int x=read();
		if((dp[x]=dp[x-1]+1)>ans) {
			ans=dp[x];
		}
	}
	printf("%d",n-ans);
	return 0;
}

T4 極品飛車
一個特殊的隱含條件是速度必須要>0,否則時間會變成負數或正無窮(長者:只有我才能操控負數和++\infin的時間,你們還是太naive)
列出式子,d1s1+c+d2s2+c+...+dnsn+c=t\frac{d_1}{s_1+c}+\frac{d_2}{s_2+c}+...+\frac{d_n}{s_n+c}=t
因爲對於任意ii,有si+c>0s_i+c>0,所以左邊是單調遞減的。
所以二分cc,暴力判即珂。

#include<stdio.h>
#include<cstring>
#include<algorithm>
#include<math.h>
#define re register int
#define mod 1000000007
#define eps 1e-10
using namespace std;
int read() {
	re x=0,f=1;
	char ch=getchar();
	while(ch<'0' || ch>'9') {
		if(ch=='-')	f=-1;
		ch=getchar();
	}
	while(ch>='0' && ch<='9') {
		x=10*x+ch-'0';
		ch=getchar();
	}
	return x*f;
}
inline char GetChar() {
	char ch=getchar();
	while(ch!='Y' && ch!='N')	ch=getchar();
	return ch;
}
const int Size=1005;
int n;
double t,s[Size],d[Size];
double check(double mid) {
	double ans=0;
	for(re i=1; i<=n; i++) {
		if(fabs(s[i]+mid)<eps) {
			ans+=1e15;
		} else {
			ans+=d[i]/(s[i]+mid);
		}
	}
	return ans;
}
int main() {
//	freopen("T4.in","r",stdin);
	n=read();
	scanf("%lf",&t);
	double minn=1e10;
	for(re i=1; i<=n; i++) {
		scanf("%lf %lf",&d[i],&s[i]);
		if(s[i]<minn)	minn=s[i];
	}
	double l=-minn+eps,r=1e7,mid;
	for(re i=1; i<=1000; i++) {
 		mid=(l+r)/2;
		if(check(mid)>=t) {
			l=mid;
		} else {
			r=mid;
		}
	}
	printf("%.6lf",l);
	return 0;
}
/*
3 9
3 2
6 3
9 4
*/

T5 修改數組
首先把所有a[i]a[i]都減去ii,然後題目變成修改一些數,要求改成非負整數,且滿足序列不減。
把所有a[i]>=0a[i]>=0a[i]a[i]提取出來,跑最長不降子序列。因爲序列不減,所以剩下的a[i]<0a[i]<0的部分一定能改成一個非負整數,使序列不減。
最後只有這個LIS的所有元素不用修改。

#include<stdio.h>
#include<cstring>
#include<algorithm>
#include<math.h>
#define re register int
using namespace std;
int read() {
	re x=0,f=1;
	char ch=getchar();
	while(ch<'0' || ch>'9') {
		if(ch=='-')	f=-1;
		ch=getchar();
	}
	while(ch>='0' && ch<='9') {
		x=(x<<1)+(x<<3)+ch-'0';
		ch=getchar();
	}
	return x*f;
}
const int Size=100005;
int n,maxn,a[Size],b[Size],tree[Size];
inline int lowbit(int x) {
	return x&(-x);
}
inline void update(int x,int v) {
	for(re i=x; i<=maxn; i+=lowbit(i)) {
		if(v>tree[i]) {
			tree[i]=v;
		}
	}
}
inline int query(int x) {
	int ans=0;
	for(re i=x; i; i-=lowbit(i)) {
		if(tree[i]>ans) {
			ans=tree[i];
		}
	}
	return ans;
}
int main() {
	n=read();
	int tot=0;
	for(re i=1; i<=n; i++) {
		a[i]=read()-i;
		if(a[i]>=0) {
			b[++tot]=a[i];
		}
	}
	for(re i=1; i<=tot; i++) {
		a[i]=b[i];
	}
	sort(a+1,a+1+tot);
	maxn=unique(a+1,a+1+tot)-(a+1);
	for(re i=1; i<=tot; i++) {
		b[i]=lower_bound(a+1,a+1+maxn,b[i])-a;
	}
	int ans=0;
	for(re i=1; i<=tot; i++) {
		int x=query(b[i]);
		update(b[i],x+1);
		if(x+1>ans) {
			ans=x+1;
		}
	}
	printf("%d",n-ans);
	return 0;
}
/*
12
3 3 6 6 1 2 6 1 1 3 6 4
*/

T6 小Biu看電影
不知道爲什麼珂以暴力dfs……

#include<stdio.h>
#include<cstring>
#include<algorithm>
#include<math.h>
#define re register int
#define mod 1000000007
using namespace std;
int read() {
	re x=0,f=1;
	char ch=getchar();
	while(ch<'0' || ch>'9') {
		if(ch=='-')	f=-1;
		ch=getchar();
	}
	while(ch>='0' && ch<='9') {
		x=10*x+ch-'0';
		ch=getchar();
	}
	return x*f;
}
const int Size=300005;
const int INF=0x3f3f3f3f;
int n,m,cnt,head[Size];
struct Edge {
	int v,t,next;
} w[Size<<1];
void AddEdge(int u,int v,int c) {
	w[++cnt].v=v;
	w[cnt].t=c;
	w[cnt].next=head[u];
	head[u]=cnt;
}
int ans=INF,val[Size],dis[Size];
void dfs(int x,int sum) {
	if(sum>=ans)	return;
	if(sum+val[x]<ans) {
		ans=sum+val[x];
	}
	for(int i=head[x]; i; i=w[i].next) {
		int nxt=w[i].v;
		if(sum+w[i].t<dis[nxt]) {
			dis[nxt]=sum+w[i].t;
			dfs(nxt,sum+w[i].t);
		}
	}
}
int main() {
//	freopen("T6.in","r",stdin);
	n=read();
	m=read();
	for(re i=1; i<=n; i++) {
		val[i]=read();
	}
	for(re i=1; i<=m; i++) {
		int u=read();
		int v=read();
		int c=read()<<1;
		AddEdge(u,v,c);
		AddEdge(v,u,c);
	}
	for(re i=1; i<=n; i++) {
		memset(dis,0x3f,sizeof(dis));
		ans=val[i];
		dfs(i,0);
		printf("%d\n",ans);
	}
	return 0;
}

正解:
建一個虛點ss,從ss向所有ii連邊權爲val[i]val[i]的邊,跑dijkstra。
然後ss到每個點的距離就是從這個點開始能看到電影的最小花費(容易看出最小花費就是ss到一個點的最短距離,因爲一開始建了邊權爲val[i]val[i]的邊)。

#include<stdio.h>
#include<cstring>
#include<algorithm>
#include<queue>
#define re register int
#define mod 1000000007
using namespace std;
int read() {
	re x=0,f=1;
	char ch=getchar();
	while(ch<'0' || ch>'9') {
		if(ch=='-')	f=-1;
		ch=getchar();
	}
	while(ch>='0' && ch<='9') {
		x=10*x+ch-'0';
		ch=getchar();
	}
	return x*f;
}
const int Size=100005;
const int INF=0x3f3f3f3f;
int n,m,cnt,head[Size];
struct Edge {
	int v,t,next;
} w[600005];
void AddEdge(int u,int v,int c) {
	w[++cnt].v=v;
	w[cnt].t=c;
	w[cnt].next=head[u];
	head[u]=cnt;
}
struct node {
	int x,t;
};
inline bool operator < (const node a,const node b) {
	return a.t>b.t;
}
int dis[Size];
void Dijkstra(int s) {
	memset(dis,0x3f,sizeof(dis));
	priority_queue<node> Q;
	Q.push((node){s,0});
	dis[s]=0;
	while(!Q.empty()) {
		int x=Q.top().x;
		Q.pop();
		for(re i=head[x]; i; i=w[i].next) {
			int nxt=w[i].v;
			if(dis[x]+w[i].t<dis[nxt]) {
				dis[nxt]=dis[x]+w[i].t;
				Q.push((node){nxt,dis[nxt]});
			}
		}
	}
}
int main() {
//	freopen("T6.in","r",stdin);
	n=read();
	m=read();
	int s=n+1;
	for(re i=1; i<=n; i++) {
		int x=read();
		AddEdge(s,i,x);
	}
	for(re i=1; i<=m; i++) {
		int u=read();
		int v=read();
		int c=read()<<1;
		AddEdge(u,v,c);
		AddEdge(v,u,c);
	}
	Dijkstra(s);
	for(re i=1; i<=n; i++) {
		printf("%d\n",dis[i]);
	}
	return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章