NOIP模拟题题解

这套题是一位学长出的=-=关于我们热爱的小机房(但由于强行用梗,部分题意不清),很不幸的是我那天刚好秀逗了,成为了唯一一个爆零的

Day 1:

这天我整个人都是傻的,于是我不出意料的成为唯一一个爆零的= =

1.【真●翻转游戏】

flip.cpp

【题目描述】

“4*4的翻转游戏太简单了”,kkke心想,“如果变成n*n的会怎么样?”

于是kkke找来了一个更大的棋盘(其实就是纸上画的),在棋盘上的每个格子上都放上棋子,每个棋子有黑白两面,最初有的棋子黑色向上,有的白色向上。翻转的规则一样,就是要用最少的翻转次数来使所有棋子向上的都是同一个颜色。每一次翻转,kkke会选择任意一个棋子,将它和上下左右共5个棋子一同翻转。

 

【输入】

第一行:整数n,表示棋盘有n*n个格子

接下来n行:每行包括n个字母,表示初始的每个棋子的状态。w表示这个棋子白色向上, b表示这个棋子当前是黑色向上的。

 

【输出】

输出为一行,如果无法达到目标状态,则输出“Impossible\n”,否则输出一个整数,表示kkke最少需要翻转的次数。

【输入样例】

4

bwwb

bbwb

bwwb

bwww

【输出样例】

4

【数据规模】

30%的数据满足:n<=4

100%的数据满足:n<=16

搜索。先搜索第一层的所有情况,由此判断整个棋盘的情况。代码内有详解。

#include<cstdio>//搜索 
#include<algorithm>
#include<cstring>
using namespace std;
const int inf=0x7f7f7f;
char str[20][20];
int map[20][20];
int n;
int work(int c)
{
	int q=1<<n;//2^n;因为第一层有n个棋子每个棋子有两种颜色,所以枚举情况为2^n种 
	int ans=inf;
	for(int k=0;k<q;k++)//搜索第一层的所有情况 
	{
		int step=0;//记录操作步数 
		for(int j=0;j<n;j++)//初始化:将字符转化为数字 
		{
			for(int i=0;i<n;i++)
			{
				if(str[j][i]=='b') map[j][i]=1;
				else map[j][i]=0;
			}
		}
		for(int i=0;i<n;i++)//改变第一层的状态 
		{
			if(k&(1<<i)) continue;k表示状态,i要和要改变成的颜色一致****** 
			step++;
			map[0][i]=1-map[0][i];//取反
			if(i>0) map[0][i-1]=1-map[0][i-1];//左边有棋子 
			if(i<n-1) map[0][i+1]=1-map[0][i+1];//右边有棋子 
			if(n>1) map[1][i]=1-map[1][i];//下面有棋子 
		}
		for(int i=1;i<n;i++)
		{
			for(int j=0;j<n;j++)
			{
				if(map[i-1][j]==c) continue;//如果上一层对应位置不是目的状态  
				step++;//则将当前位置翻面  
				map[i][j]=1-map[i][j];
				map[i-1][j]=c;//***
				if(i>0) map[i][j-1]=1-map[i][j-1];
		    	if(j<n-1) map[i][j+1]=1-map[i][j+1]; 
		    	if(i<n-1) map[i+1][j]=1-map[i+1][j];//***
			}
		}
		bool flag=true;
		for(int i=0;i<n;i++)//判断最后一层是否是目的状态
		{
			if(map[n-1][i]!=c)
			{
				flag=false;
				break;
			}
		}
		if(flag)
		{
			ans=min(ans,step);//若最后一层满足则一定到达目的状态
		}
	}
	return ans;
}
int main()
{
	freopen("flip.in","r",stdin);
	freopen("flip.out","w",stdout);
	scanf("%d",&n);
	for(int i=0;i<n;i++)
	{
		scanf("%s",str[i]);
	}
	int ans=min(work(1),work(0));
	if(ans==inf) printf("Impossible\n");
	else printf("%d\n",ans);
	return 0;
}

2.【丑数】

humble.cpp

【题目描述】

如果一个数没有2,3,5,7以外的素数因子,那么这个数被称为“丑数”,又称“humble number”。

这里列出前几个“丑数”:1,2,3,4,5,6,7,8,9,10,12,14,15,16,18,20,21,24,25,27。经验证,2000000000以内的“丑数”共有5842个。

现在,icezero想知道第n个丑数(从1开始编号)是多少,但他忙着做智能手环,于是这个简单的问题只有求助各位msoier了。

 

【输入】

第一行:整数n,表示需要查找的“丑数”序号。

以后n行,第i+1行:整数ai,表示需要查找第ai个“丑数”。

 

【输出】

第i行:输出第ai个“丑数”

 

【输入样例】

3

1

11

5842

 

【输出样例

1

12

2000000000

 

【数据规模】

10%的数据满足:答案<=100,n=1

30%的数据满足:ai<=100,n<=100

100%的数据满足:a i<=5842,n<=1000

简单模拟。。也可以打表

#include<cstdio>//模拟 
#include<algorithm>
#include<cstring>
#include<cmath>
using namespace std;
int c[]={2,3,5,7};
int n;
int q[1005];
bool v[32][32][32][32];
//int sushu[105];
int t;
int num[6000];//记录丑数的编号; 
bool check(long long x)
{
	if(x>2000000000||x<0) return 0;
	int a=0,b=0,c=0,d=0; 
	while(x%2==0){
		x=x/2;
		a++;
	}
	while(x%3==0)
	{
		x=x/3;
		b++;
	}
	while(x%5==0)
	{
		x=x/5;
		c++;
	}
	while(x%7==0)
	{
		x=x/7;
		d++;
	}
	if(v[a][b][c][d]) return 0;
	else {
		v[a][b][c][d]=1;
		return 1;
	}
}
bool compare(long a,long b)
{
	return a<b;
}
void work(long long x)
{
	for(int i=0;i<=3;i++)
	{
		long long a=c[i]*x;
		
		if(!check(a)) continue;
		num[++t]=a;
		work(a);
	}
}
int main()
{
	freopen("humble.in","r",stdin);
	freopen("humble.out","w",stdout);
	scanf("%d",&n);
	memset(v,0,sizeof(v));
	v[0][0][0][0]=1;
	num[1]=1;
	t=1;
	work(1);
	sort(num+1,num+t+1,compare);
	for(int i=1;i<=n;i++)
	{
		scanf("%d",&q[i]);
		printf("%d\n",num[q[i]]);
	}
	return 0;
}

3.【小机房危机】

crisis.cpp

【题目描述】

Stevenzzzk在得知今年的noip要开始的时候,准备会小机房看望并慰问msoiers,他的众多仆人们强烈要求要跟着去服侍他,那么问题来了,小机房怎么能容得下土豪珂的众多仆人呢,不,哪怕是整个绵实也不能,于是聪明的Rain.Xu老师想到了一个办法,选出最优秀的k个仆人分别编号为1~k,首先,第1个仆人陪同Stevenzzzk从豪宅以最短的时间走到小机房,然后在到达时开始服侍他直到下一个仆人到来(路上有专门的仆人服侍,不算在k个仆人内),所有仆人都想以最短的时间走到小机房,他们同时出发,但走过的路径不能与编号比他小的仆人完全相同,显然,编号越小的仆人越先服侍他(同时到达则一起服侍)。

整个地图有n个点(0~(n-1)),有m条单向路。现在,第k个仆人想知道自己多久才能服侍到Stevenzzzk。

 

【输入】

第一行:整数n,m,k,s(代表豪宅的点的编号),t(代表小机房的点的编号)

接下来m行:每行包括 整数a,b,T,代表从a走到b要消耗时间T;

 

【输出】

输出为一行,如果Stevenzzzk无法到达小机房,则输出“-1\n”否则输出第k个仆人开始服侍Stevenzzzk的时间。

 

【输入样例】

4 810 0 3

0 192

0 268

0 31

1 014

1 267

2 319

3 073

3 228

【输出样例】

142

【数据规模】

有10%的数据满足:k=1

另外30%的数据满足:n<=60

100%的数据满足:n<=1000,m<=100000,k<=1000,s!=t

启发式搜索+最短路 。然而当时的我并不知道什么事启发式搜索_(:з」∠)_,所以当时我根本不会做,下来过后结合标程然后查了资料才知道。

#include <cstdio>                                     
#include <cstring>                                 
#include <iostream>                                     
#include <algorithm>                               
#include <queue>
#include <vector>

#define MAXN 1010
#define MAXM 100010
#define INF 0x3f3f3f3f

using namespace std;

int n,m,K,s,t;
int dist[MAXN];
int hehe[MAXN];
int cnt[MAXN];

struct to_edge{
	int to;
	int next;
	int v;
}tedge[MAXM];

struct from_edge{
	int from;
	int next;
	int v;
}fedge[MAXM];

int thead[MAXN],fhead[MAXN],top;

queue<int>q;

struct step{
	int p,v;
	bool operator<(const step &a)const
	{
		return dist[p]+v>dist[a.p]+a.v;
	}
}nows,nexts;

priority_queue<step>p_q;

int read();

void add(int a,int b,int v)
{
	tedge[top].to=b;
	tedge[top].v=v;
	tedge[top].next=thead[a];
	thead[a]=top;
	
	fedge[top].from=a;
	fedge[top].v=v;
	fedge[top].next=fhead[b];
	fhead[b]=top++;
}

void read_data()
{
	n=read();
	m=read();
	K=read();
	s=read();
	t=read();
	if(s==t)K++; 
	for(int i=0;i<=n;i++)thead[i]=fhead[i]=-1;
	for(int i=0;i<=n;i++)dist[i]=INF;
	int a,b,v;
	for(int i=0;i<m;i++)
	{
		a=read();
		b=read();
		v=read();
		add(a,b,v);
	}
}

void spfa()
{
	dist[t]=0;
	q.push(t);
	while(!q.empty())
	{
		int nowp=q.front();q.pop();
		hehe[nowp]=false;
		for(int i=fhead[nowp];i!=-1;i=fedge[i].next)
		{
			if(dist[fedge[i].from]>dist[nowp]+fedge[i].v)
			{
				dist[fedge[i].from]=dist[nowp]+fedge[i].v;
				if(hehe[fedge[i].from])continue;
				q.push(fedge[i].from);
				hehe[fedge[i].from]=true;
			}
		}
	}
}

int astar()
{
	nows.p=s;
	nows.v=0;
	p_q.push(nows);
	while(!p_q.empty())
	{
		nows=p_q.top();p_q.pop();
		for(int i=thead[nows.p];i!=-1;i=tedge[i].next)
		{
			nexts.p=tedge[i].to;
			nexts.v=nows.v+tedge[i].v;
			cnt[nexts.p]++;
			if(nexts.p==t&&cnt[t]==K)return nexts.v;
			if(cnt[nexts.p]<=K)p_q.push(nexts);
		}
	}
	return -1;
}

int main()
{
	freopen("crisis.in","r",stdin);
	freopen("crisis.out","w",stdout);
	read_data();
	spfa();
	if(dist[s]==INF)printf("-1\n");
	else printf("%d\n",astar()); 
	return 0;
}

int read()
{
	int a=0;
	char c;
	while((c=getchar())<'0'||c>'9');
	do{
		a=a*10+c-'0';
	}while((c=getchar())>='0'&&c<='9');
	return a;
}


Day 2:

于是第二天我决定虐场=-=。。。

1.【堆快递】

express.cpp

【题目描述】

CharlieYoung即使去送快递了,还是不忘他以前创造的模拟的神话,于是他找来了一些大小相同的长方体快递,并将这些快递堆放在一个n*m的矩形区域内。当然他找不到这么多相同的快递,他只是想用程序模拟而已。

在程序中每个快递用符号表示方法:每个顶点用1个加号’+’表示,长用3个’-’表示,宽用1个’/’,高用两个’|’表示。字符’+’和’-’和’/’ 和’|’的ASCII码分别为43,45,47,124。字符’.’(ASCII码46)需要作为背景输出,即立体图里的空白部分需要用’.’来代替

即每个快递表示为


需要模拟的是:堆好的快递的立体图的样子

 

【输入】

第一行:整数n,m,表示场地为n*m的

接下来n行:每行包括m个整数,第i行第j个数表示(i,j)处的快递层数

 

【输出】

输出为一行,如果无法达到目标状态,则输出“Impossible\n”,否则输出一个整数,表示kkke最少需要翻转的次数。

【输入样例】

3 4

2 21 2

2 21 1

3 21 2

 

 

【输出样例】


【数据规模】

有10%的数据满足:n=1;

另10%的数据满足:m=1;

另10%的数据满足:最高层数=1;

100%的数据满足:1<=m,n<=50,最高层数<=100


直接模拟,不说了= =,最开始先把背景图建好(即一个全是‘.’的图),然后通过n和m的关系来确定图的大小。
ps:= =本人代码比较粗暴,如要往下阅读请做好心理准备。。。
#include<algorithm>//【模拟】从前往后填充 从左往右填
#include<cstdio>
using namespace std;
int m;
int n;
char a[500][500];
int map[51][51];
int map1[51][51];
int maxh=-1;
int maxw=-1;
int main()
{
	freopen("express.in","r",stdin);
	freopen("express.out","w",stdout);
	scanf("%d%d",&m,&n);
	for(int i=m;i>=1;i--)
    for(int j=n;j>=1;j--)
    {
    	scanf("%d",&map1[i][j]);
    	maxh=max(maxh,map1[i][j]*3+(i-1)*2+3);
    	map[i][n+1-j]=map1[i][j];
    }
    maxw=n*4+1+m*2;
    for(int i=1;i<=maxh;i++)
    {
    	for(int j=1;j<=maxw;j++)
    	{
    		a[i][j]=46;
    	}
    }
    for(int i=m;i>=1;i--)
    {
    	for(int j=1;j<=n;j++)
    	{
    		if(map[i][j]!=0)
    		{
    			int k=3;
				a[maxh-(i-1)*2][j*4-4+1+(i-1)*2]='+';
    			a[maxh-(i-1)*2][j*4-4+2+(i-1)*2]='-';
    			a[maxh-(i-1)*2][j*4-4+3+(i-1)*2]='-';
    			a[maxh-(i-1)*2][j*4-4+4+(i-1)*2]='-';
    			a[maxh-(i-1)*2][j*4-4+5+(i-1)*2]='+';//
    			a[maxh-(i-1)*2-1][j*4-4+1+(i-1)*2]='|';
    			a[maxh-(i-1)*2-1][j*4-4+2+(i-1)*2]=' ';
    			a[maxh-(i-1)*2-1][j*4-4+3+(i-1)*2]=' ';
    			a[maxh-(i-1)*2-1][j*4-4+4+(i-1)*2]=' ';
    			a[maxh-(i-1)*2-1][j*4-4+5+(i-1)*2]='|';
    			a[maxh-(i-1)*2-1][j*4-4+6+(i-1)*2]='/';
    			map[i][j]--;
    			while(map[i][j]>0)
    			{
    				a[maxh-(i-1)*2-k+1][j*4-4+1+(i-1)*2]='|';
    	     		a[maxh-(i-1)*2-k+1][j*4-4+2+(i-1)*2]=' ';
    	     		a[maxh-(i-1)*2-k+1][j*4-4+3+(i-1)*2]=' ';
    	     		a[maxh-(i-1)*2-k+1][j*4-4+4+(i-1)*2]=' ';
    	    		a[maxh-(i-1)*2-k+1][j*4-4+5+(i-1)*2]='|';
    	    		a[maxh-(i-1)*2-k+1][j*4-4+6+(i-1)*2]=' ';
    	    		a[maxh-(i-1)*2-k+1][j*4-4+7+(i-1)*2]='+';
    	    		k++;
    	    		a[maxh-(i-1)*2-k+1][j*4-4+1+(i-1)*2]='+';
    	     		a[maxh-(i-1)*2-k+1][j*4-4+2+(i-1)*2]='-';
    	     		a[maxh-(i-1)*2-k+1][j*4-4+3+(i-1)*2]='-';
    	     		a[maxh-(i-1)*2-k+1][j*4-4+4+(i-1)*2]='-';
    	    		a[maxh-(i-1)*2-k+1][j*4-4+5+(i-1)*2]='+';
    	    		a[maxh-(i-1)*2-k+1][j*4-4+6+(i-1)*2]=' ';
    	    		a[maxh-(i-1)*2-k+1][j*4-4+7+(i-1)*2]='|';
    	    		k++;
    	    		a[maxh-(i-1)*2-k+1][j*4-4+1+(i-1)*2]='|';
    	     		a[maxh-(i-1)*2-k+1][j*4-4+2+(i-1)*2]=' ';
    	     		a[maxh-(i-1)*2-k+1][j*4-4+3+(i-1)*2]=' ';
    	     		a[maxh-(i-1)*2-k+1][j*4-4+4+(i-1)*2]=' ';
    	    		a[maxh-(i-1)*2-k+1][j*4-4+5+(i-1)*2]='|';
    	    		a[maxh-(i-1)*2-k+1][j*4-4+6+(i-1)*2]='/';
    	    		a[maxh-(i-1)*2-k+1][j*4-4+7+(i-1)*2]='|';
    	    		k++;
    	    		map[i][j]--;
    			}
    			a[maxh-(i-1)*2-k+1][j*4-4+1+(i-1)*2]='|';
    	     	a[maxh-(i-1)*2-k+1][j*4-4+2+(i-1)*2]=' ';
    	     	a[maxh-(i-1)*2-k+1][j*4-4+3+(i-1)*2]=' ';
    	    	a[maxh-(i-1)*2-k+1][j*4-4+4+(i-1)*2]=' ';
    	    	a[maxh-(i-1)*2-k+1][j*4-4+5+(i-1)*2]='|';
    	   		a[maxh-(i-1)*2-k+1][j*4-4+6+(i-1)*2]=' ';
    	   		a[maxh-(i-1)*2-k+1][j*4-4+7+(i-1)*2]='+';
    	   		k++;
    	   		a[maxh-(i-1)*2-k+1][j*4-4+1+(i-1)*2]='+';
    	     	a[maxh-(i-1)*2-k+1][j*4-4+2+(i-1)*2]='-';
    	     	a[maxh-(i-1)*2-k+1][j*4-4+3+(i-1)*2]='-';
    	   		a[maxh-(i-1)*2-k+1][j*4-4+4+(i-1)*2]='-';
    	   		a[maxh-(i-1)*2-k+1][j*4-4+5+(i-1)*2]='+';
    	   		a[maxh-(i-1)*2-k+1][j*4-4+6+(i-1)*2]=' ';
    	   		a[maxh-(i-1)*2-k+1][j*4-4+7+(i-1)*2]='|';
    	   		k++;
    	   		a[maxh-(i-1)*2-k+1][j*4-4+2+(i-1)*2]='/';
    	     	a[maxh-(i-1)*2-k+1][j*4-4+3+(i-1)*2]=' ';
    	     	a[maxh-(i-1)*2-k+1][j*4-4+4+(i-1)*2]=' ';
    	     	a[maxh-(i-1)*2-k+1][j*4-4+5+(i-1)*2]=' ';
    	    	a[maxh-(i-1)*2-k+1][j*4-4+6+(i-1)*2]='/';
    	    	a[maxh-(i-1)*2-k+1][j*4-4+7+(i-1)*2]='|';
    	    	k++;
    	     	a[maxh-(i-1)*2-k+1][j*4-4+3+(i-1)*2]='+';
    	     	a[maxh-(i-1)*2-k+1][j*4-4+4+(i-1)*2]='-';
    	     	a[maxh-(i-1)*2-k+1][j*4-4+5+(i-1)*2]='-';
    	    	a[maxh-(i-1)*2-k+1][j*4-4+6+(i-1)*2]='-';
    	    	a[maxh-(i-1)*2-k+1][j*4-4+7+(i-1)*2]='+';
    		}
    	}
    }
    for(int i=1;i<=maxh;i++)
    {
    	for(int j=1;j<=maxw;j++)
    	{
    		printf("%c",a[i][j]);
    	}
    	printf("\n");
    }
    return 0;
}



2.【骗分】

cheat.cpp

【题目描述】

return0可是骗分界的高手,曾经通过输出”1\n”就拿下了40%的数据,而今天他要做的题可不是仅仅输1那么简单,经过他高端的分析,发现有n和k两个输入特别显眼,在多次测试后,发现了一个骗分的方法,在1~n共n个数中取k个出来,计算这些数的最大公约数(设1个数的最大公约数是其本身),当这k个数的最大公约数在所有取法中最大的时候。将这个最大的最大公约数输出,居然能够AC那道难题,小机房的伙伴们都惊叹于return0的骗分之术。但传奇的背后,还有一个问题,虽然这种骗分法比直接做原题简单,但怎么才能求出最大公约数最大的k个数的组合呢?

 

【输入】

第一行:整数n,k

 

【输出】

第一行:输出找出这k个数的最大公约数

 

【输入样例】

4 2

 

【输出样例】

2

 

【数据规模】

10%的数据满足:1<=k<=n<=10

40%的数据满足:1<=k<=n<=106

100%的数据满足:1<=k<=n<=1066

通过证明我们可以知道这道题其实就是用n/k就可以了= =(这里就不给出证明了,因为我是看出来的=-=)
我们十分单纯的学长(出题人)下来还一脸委屈的说,_(:з」∠)_他还想把这道题当做压轴题呢,结果被机智的我们一秒看破_(:з」∠)_。
首先看到这个数据。。。= =10 66,整个人都是醉的啊。。
所以这道题就转化为了高精除高精:
#include<cstdio>//高精除高精 n/k 
#include<algorithm>
#include<cstring>
using namespace std;
int a[201];
int b[201];
int c[201];

void init(int a[])//字符串转换 
{
	char c[100];
	scanf("%s",c);
	a[0]=strlen(c);//记录长度 
	for(int i=1;i<=a[0];i++)
	{
		a[i]=c[a[0]-i]-'0';
	}
}
void printf(int a[])//输出转化 
{
	if(a[0]==0) {printf("0\n");
	return;
	}
	for(int i=a[0];i>=1;i--)
	{
		printf("%d",a[i]);
	}
	printf("\n");
	return;
}
int compare(int a[],int b[])//比较 
{
	if(a[0]>b[0]) return 1;
	if(a[0]<b[0]) return -1;
	//如果位数相同 比较每一位 
	for(int i=a[0];i>=1;i--)
	{
		if(a[i]>b[i]) return 1;
		if(a[i]<b[i]) return -1;
	}
	return 0;
}
void jian(int a[],int b[])//做减法
{
	int flag=compare(a,b);
	if(flag==0) {// 
		a[0]=0;
		return;
	}
	if(flag==1)
	{
		for(int i=1;i<=a[0];i++)
		{
			if(a[i]<b[i])
			{
				a[i+1]--;
				a[i]+=10;
			}
			a[i]-=b[i];
		}
		
		while(a[0]>0&&a[a[0]]==0) a[0]--;
		return;
	}
}
void work(int p[],int q[],int d)
{
	for(int i=1;i<=p[0];i++)
	{
		q[i+d-1]=p[i];
	}
	q[0]=p[0]+d-1;
}
void chu(int a[],int b[],int c[])//不断地减,直到减到小于除数,然后减的次数加起来,就是商
{
	int t[101];
	c[0]=a[0]-b[0]+1;
	for(int i=c[0];i>=1;i--)
	{
		memset(t,0,sizeof(t));
		work(b,t,i);
		while(compare(a,t)>=0) {
			c[i]++;
			jian(a,t);
		}
	}
	while(c[0]>0&&c[c[0]]==0) c[0]--;
	return;
}
int main()
{
	freopen("cheat.in","r",stdin);
    freopen("cheat.out","w",stdout);
	memset(a,0,sizeof(a));
	memset(b,0,sizeof(b));
	memset(c,0,sizeof(c));
	init(a);
	init(b);
	chu(a,b,c);
	printf(c);
	return 0;
}

3.【矩阵乘法】

matrix.cpp

【题目描述】

在矩阵乘法中,若要使矩阵A和B可乘,需满足矩阵A的列数等于矩阵B的行数。,例如:若A是一个p×q的矩阵,B是一个q×r的矩阵,则A,B可乘,其乘积C=A×B是一个p×r的矩阵。

计算矩阵乘法C=A×B的常规方法是:

for(inti=0;i<p;i++)

{

    for(int j=0;j<r;j++)

{

    C[i][j]=0;

    for(intk=0;k<q;k++)C[i][j]+=A[i][k]*B[k][j];

}

}

现在,刘莫意又开始莫得意思了,他想知道n个矩阵的连乘用这种方法最少需要计算多少次乘法。

 

【输入】

第一行:整数n,代表矩阵的个数

接下来n行:每行包括 整数ai,bi 代表第i个矩阵有ai行,bi列(保证相邻矩阵之间可乘)。

 

【输出】

输出为一行,一个整数 表示计算最少需要的乘法次数;

 

【输入样例】

2

1 2

2 3

 

【输出样例】

6

 

【数据规模】

有10%的数据满足:n=2

100%的数据满足:n<=10, a i,b i<=100
这道题就无耻了_(:з」∠)_,打着矩阵乘法的旗号来考简单dp,机房里一位妹子下来知道这是dp过后感觉痛不欲生=-=
(因为她看到矩阵乘法就觉得不会于是直接放弃_(:з」∠)_)
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int n;
int a[11];
int b[11];
int dp[11][11];

int main()
{
	freopen("matrix.in","r",stdin);
	freopen("matrix.out","w",stdout);
	scanf("%d",&n);
	memset(dp,0x7f7f7f,sizeof(dp));
	for(int i=1;i<=n;i++)
	{
		scanf("%d %d",&a[i],&b[i]);
		dp[i][i]=0;
	}
	for(int i=n-1;i>=1;i--)//枚举每个矩阵的起点 
	{
		for(int j=i+1;j<=n;j++)//枚举终点 
		{
			for(int k=i;k<=j-1;k++)//中间节点 
			{
				dp[i][j]=min(dp[i][j],dp[i][k]+dp[k+1][j]+a[i]*a[k+1]*b[j]);
			}
		}
	}
	printf("%d",dp[1][n]);
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值