3.25考试

WG一言不合又考试了。。。

题目不难

考得很萎

不知考啥

1、简单的数列

Description
一个简单的数列问题: 
给定一个长度为n的数列,求这样的三个元素 ai,aj,ak 的个数,满足 ai<aj>ak,且 i<j<k 。

Input
第1行是一个整数n(1<=n<=50000)。 
接下来n行,每行一个元素ai(0<=ai<=32767)。

Output
一个数,满足 ai<aj>ak (i<j<k) 的个数。

Sample Input





1

Sample Output
6

Hint
数据范围: 
对于30%的输入数据有n<=200。 
对于80%的输入数据有n<=10000。 
对于100%的输入数据有n<=50000。

树状数组记录每个数左边有几个数比它小,右边有几个数比他小,相乘,再全部相加就是答案,应该很好证吧

#include<cstdio>
#include<algorithm>
#include<cstring>
#define lb(o) ((o)&(-(o)))
#define File(a) freopen(a".in","r",stdin);freopen(a".out","w",stdout);
using namespace std;
int T[32800],L[50002],R[50002];
int num[50002];
int n;
inline void update(int r){
	while(r<=32768)++T[r],r+=lb(r);
}
inline int sum(int r){
	int ans=0;
	while(r)ans+=T[r],r-=lb(r);
	return ans;
}
inline int gi(){
	int x=0,f=1;char ch=getchar();
	while(ch>'9'||ch<'0')f=(ch=='-')?-1:f,ch=getchar();
	while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar();
	return x*f;
}
int main(){
	n=gi();
	for(int i=1;i<=n;i++)num[i]=gi()+1;
	memset(T,0,sizeof T);
	for(int i=1;i<=n;i++){
		int now=num[i];
		update(now);
		L[i]=sum(now-1);
	}
	memset(T,0,sizeof T);
	for(int i=n;i;i--){
		int now=num[i];
		update(now);
		R[i]=sum(now-1);
	}
	long long ans=0;
	for(int i=1;i<=n;i++)ans+=L[i]*R[i];
	printf("%lld",ans);
	return 0;
}
 



2、黄金矿工

Description
黄金矿工是一个经典的小游戏,它可以锻炼人的反应能力。该游戏中,可以通过“挖矿”获得积分并不断升级。玩家可以在线玩flash版黄金矿工,也可以下载后玩单机版黄金矿工。目前,黄金矿工小游戏有多个版本,例如黄金矿工双人版,黄金矿工单人版等。

Jimmy是一位黄金矿工,他所在的金矿是一个n*n的矩形区域(俯视),区域内有黄金、石头和TNT,由一个 n*n的矩阵描述。黄金的价值对应矩阵中的正值,石头的价值对应矩阵中的负值,TNT由0表示。换句话说,挖到黄金赚钱,石头亏损,如果挖到TNT就挂了。

Jimmy租到的挖矿工具很特别,它的形状是一个长宽任意(均为正整数)的矩形,可以取走被该工具覆盖的矩形区域内的所有物品,但如果该区域内有TNT,该工具将被炸毁,此时Jimmy将不得不赔偿矿主+∞元!!!需要注意的是,该工具只能在金矿范围内使用(即不得超出金矿边界),且租金为每次使用十元。

现在,Jimmy想知道,如果他至多只有一次租用该工具的机会,他能获得的最大收益是多少。当然,如果Jimmy租用该工具无论如何都会亏损,他可以不租用,此时收益为0.

Input
第一行:一个整数n 
接下来n行,每行n个整数(绝对值<100),为题目中所描述的矩阵。

Output
一个数,即Jimmy所能获得的最大收益。

Sample Input

0 -1 -1 
0 -12 0 
-19 0 0

Sample Output
0

Hint
【样例解释】 
无论Jimmy怎么挖矿,挖到的不是石头,就是TNT,总之无论如何都会亏损,所以选择不租用工具,收益为0

【数据范围】 
对于30%的数据:0<n<=10
对于60%的数据:0<n<=100
对于100%的数据:0<n<=300


TNT权值设为-∞就好了

DP。一维的最大数列满足决策单调性,然后将二维的压成一维的,n3次方过(考场上写的n4次方,感谢ZJG大佬,%%%%%%%)(ZJG大佬今天要AK的,只是没注意上方红字,呵呵)(今天全是暴力还有第二,呵呵)

深入理解一下。这样的矩阵:

当i==2 j==4时

被压缩成了这样。


再跑DP

#include<cstdio>
#include<algorithm>
#define File(a) freopen(a".in","r",stdin);freopen(a".out","w",stdout);
#define rg register
using namespace std;
int T[310][310],n;
inline int gi() {
	rg int x=0,f=1;
	char ch=getchar();
	while(ch>'9'||ch<'0')f=(ch=='-')?-1:f,ch=getchar();
	while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar();
	return x*f;
}
inline int QT(int x,int y,int xx,int yy) {
	return T[xx][yy]-T[xx][y-1]-T[x-1][yy]+T[x-1][y-1];
}
int main() {
	rg int num;
	n=gi();
	for(rg int i=1; i<=n; i++)
		for(rg int j=1; j<=n; j++) {
			num=gi();
			if(num==0)num=-10000000;
			T[i][j]=T[i-1][j]+num;
		}
	rg int ans=0;
	for(rg int i=1; i<=n; i++)
		for(rg int j=i; j<=n; j++) {
			int sum=T[j][1]-T[i-1][1];
			int Sum=sum;
			ans=max(ans,Sum);
			for(int k=2;k<=n;k++){
				sum=T[j][k]-T[i-1][k];
				if(Sum>0)Sum+=sum;
				else Sum=sum;
				ans=max(ans,Sum);
			}
		}
	ans=max(ans-10,0);
	printf("%d",ans);
	return 0;
}



3、旅行

Description
Z小镇是一个景色宜人的地方,吸引来自各地观光客来此旅游观光。Z小镇附近共有N个景点(编号为1,2,3...N),这些景点被M条道路连接着,所有道路都是双向的,两个景点之间可能有多条道路连接着。也许是为了保护该地的旅游资源,Z小镇有个奇怪的规定,就是对于一条给定的公路Ri,任何在该公路上行驶的车辆速度必须为Vi。速度变化太快使得游客们很不舒服,因此从一个景点前往另一个景点的时候,大家都希望选择行使过程中最大速度和最小速度的比尽可能小的路线,也就是所谓最舒适路线。

Input
第一行包括两个整数: N 和 M 
接下来的M行每行包含三个正整数: x,y和v。表示景点x到景点y之间有一条双向公路,车辆必须以速度v在该公路上行驶。最后一行包含两个正整数s,t,表示想知道从景点s到景点t最大最小速度比最小的路径。s和t不可能相同。

Output
如果景点s到景点t没有路径,输出“IMPOSSIBLE”。否则输出一个数,表示最小的速度比。如果需要,输出一个既约分数。

Sample Input
样例1: 
4 2 
1 2 1 
3 4 2 
1 4 
样例2: 
3 3 
1 2 10 
1 2 5 
2 3 8 
1 3 
样例3: 
3 2 
1 2 2 
2 3 4 
1 3

Sample Output
样例1: 
IMPOSSIBLE 
样例2: 
5/4 
样例3: 
2

Hint
0<N<=500; 
0<M<=5000;


把边排个序,枚举最小的边(分母),再往上加边并合并并查集,起点和原点在一起了就输出当前权值。(%%%ZJG)

#include<cstdio>
#include<algorithm>
#define File(a) freopen(a".in","r",stdin);freopen(a".out","w",stdout);
using namespace std;
const int maxn=510,maxm=5010<<1;
inline int gi() {
	int x=0,f=1;
	char ch=getchar();
	while(ch>'9'||ch<'0')f=(ch=='-')?-1:f,ch=getchar();
	while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar();
	return x*f;
}
struct E {
	int a,b,w;
} e[5001];
bool cmp(E a,E b) {
	return a.w<b.w;
}
int f[501];
inline int head(int r) {
	int A=r,B;
	while(A^f[A])A=f[A];
	while(r^A)B=f[r],f[r]=A,r=B;
	return A;
}
int main() {
	int n=gi(),m=gi();
	for(int i=1; i<=m; i++)e[i].a=gi(),e[i].b=gi(),e[i].w=gi();
	int s=gi(),t=gi();
	int ansa=2,ansb=20000000;
	sort(e+1,e+m+1,cmp);
	for(int i=1; i<=m; i++) {
		for(int j=1; j<=n; j++)f[j]=j;
		for(int j=i; j<=m; j++) {
			f[head(e[j].a)]=head(e[j].b);
			if(head(s)==head(t)) {
				if(e[i].w*ansb>ansa*e[j].w)ansa=e[i].w,ansb=e[j].w;
				break;
			}
		}
	}
	if(ansa==2&&ansb==20000000)printf("IMPOSSIBLE");
	else {
		int a=ansa,b=ansb,c;
		while(a%b)c=a%b,a=b,b=c;
		if(b^ansa)printf("%d/%d",ansb/b,ansa/b);
		else printf("%d",ansb/b);
	}
	return 0;
}
4、奶牛跑步(K短路)

Description
Bessie准备用从牛棚跑到池塘的方法来锻炼. 但是因为她懒,她只准备沿着下坡的路跑到池塘,然后走回牛棚.

Bessie也不想跑得太远,所以她想走最短的路经. 农场上一共有M(1<=M<=10,000)条路,每条路连接两个用1..N(1<=N<=1000)标号的地点. 更方便的是,如果X>Y,则地点X的高度大于地点Y的高度. 地点N是Bessie的牛棚;地点1是池塘.

很快, Bessie厌倦了一直走同一条路.所以她想走不同的路,更明确地讲,她想找出K(1<=K<=100)条不同的路经.为了避免过度劳累,她想使这K条路径为最短的K条路径.

请帮助Bessie找出这K条最短路经的长度.你的程序需要读入农场的地图, 一些从Xi到Yi的路径和它们的长度(Xi,Yi,Di). 
所有(Xi,Yi,Di) 满足( 1<=Yi<Xi; Yi<Xi<=N, 1<=Di<=1,000,000 ).

Input
第1行: 3个数: N,M,K 
第2..M+1行: 第 i+1行包含3个数 Xi,Yi,Di, 表示一条下坡的路.

Output
第1..K行: 第i行包含第i最短路径的长度,或?1如果这样的路径不存在.如果多条路径有同样的长度,请注意将这些长度逐一列出.

Sample Input
5 8 7 
5 4 1 
5 3 1 
5 2 1 
5 1 1 
4 3 4 
3 1 1 
3 2 1 
2 1 1

Sample Output






-1

Hint
【样例解释】 
路径分别为(5-1),(5-3-1),(5-2-1),(5-3-2-1),(5-4-3-1),(5-4-3-2-1)

裸A*+SPFA优化(考场上竟然写了裸深搜,SPFA还为了,最后T1WA2,呵呵)

#include<cstdio>
#include<algorithm>
#include<queue>
#define File(a) freopen(a".in","r",stdin);freopen(a".out","w",stdout);
using namespace std;
const int maxn=1010,maxm=10010<<1,maxk=110;
int fir[maxn],nxt[maxm],dis[maxm],w[maxm],S[maxn],ans[maxk],rev[maxm];
int n,m,k,id;
inline int gi() {
	int x=0,f=1;
	char ch=getchar();
	while(ch>'9'||ch<'0')f=(ch=='-')?-1:f,ch=getchar();
	while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar();
	return x*f;
}
inline void adde(int a,int b,int c,int d) {
	nxt[++id]=fir[a],fir[a]=id,dis[id]=b,w[id]=c,rev[id]=d;
}
struct node {
	int n,r;
};
bool operator <(node me,node ot) {
	return S[me.n]+me.r>S[ot.n]+ot.r;
}
inline void AStar() {
	priority_queue<node>as;
	as.push((node) {n,0});
	int C=0;
	while(!as.empty()&&(C^k)) {
		int now=as.top().n,R=as.top().r;
		if(now==1) {
			++C;
			ans[++ans[0]]=R;
		} else
			for(int i=fir[now]; i; i=nxt[i])
				if(rev[i])as.push((node) {dis[i],R+w[i]});
		as.pop();
	}
}
inline void spfa() {
	int que[maxn],hd=1,tl=2;
	bool in[maxn]= {0};
	que[1]=1;
	in[1]=1;
	for(int i=2; i<=n; i++)S[i]=1000000000;
	while(hd^tl) {
		int f=que[hd];
		for(int i=fir[f]; i; i=nxt[i])
			if(!rev[i]) {
				if(S[f]+w[i]<S[dis[i]]) {
					S[dis[i]]=S[f]+w[i];
					if(!in[dis[i]])que[tl++]=dis[i],in[dis[i]]=1;
				}
				if(tl==1003)tl=1;
			}
		if(++hd==1003)hd=1;
		in[f]=0;
	}
}
int main() {
	n=gi(),m=gi(),k=gi();
	int a,b,c;
	for(int i=1; i<=m; i++) {
		a=gi(),b=gi(),c=gi();
		adde(a,b,c,1);
		adde(b,a,c,0);
	}
	spfa();
	AStar();
	for(int i=1; i<=ans[0]; ++i)printf("%d\n",ans[i]);
	for(int i=k-ans[0]; i; --i)printf("-1\n");
	return 0;
}

最后%%%AK大神ZJG

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值