月考简要题解

模拟赛简要题解

一下题目均可在loj上找到

10178. 「一本通 5.5 例 4」旅行问题

简单题,将n扩大到2 * n,单调队列即可,注意正反向.

#include<iostream>  
#include<cstring>  
#include<cmath>  
#include<cstdio>  
#include<algorithm>  
using namespace std;  
typedef long long ll;  
const int N=2000005;
ll sum[N];
int p[N],d[N],que[N],ok[N];
int n;

inline int read() {
	int x = 0,f = 1;char c = getchar();
	while(c < '0' || c > '9') {if(c == '-')f = -1;c = getchar();}
	while(c >= '0' && c <= '9') {x = x * 10 + c - '0';c = getchar();}
	return x * f;
}
void DP1()
{
	int q1 = 1,q2 = 0;
	for (int i = 1; i <= n; ++ i){
		while (q1 <= q2 && sum[que[q2]] >= sum[i]) -- q2;
		que[++ q2]=i;
	}
	for (int i = n + 1; i <= n * 2; ++ i){
		while (q1 <= q2 && sum[que[q2]] >= sum[i]) -- q2;
		que[++ q2] = i;
		while (q1 <= q2 && que[q1] <= i - n) ++ q1;
		if (sum[que[q1]] >= sum[i - n]) ok[i-n] = 1;	
	}
}
void DP2()
{
	int q1 = 1,q2 = 0;
	for (int i = n * 2; i > n; -- i){
		while (q1 <= q2 && sum[que[q2]] >= sum[i]) -- q2;
		que[++ q2] = i;
	}
	for (int i = n; i; -- i){
		while (q1 <= q2 && sum[que[q2]] >= sum[i]) -- q2;
		que[++ q2] = i;
		while (q1 <= q2 && que[q1] >= i + n) ++ q1;
		if (sum[que[q1]] >= sum[i + n]) ok[i] = 1;		
	}
}
int main()  
{  
 	n = read();
 	for(int i = 1;i <= n;++ i) {
 		p[i + n] = p[i] = read(),d[i + n] = d[i] = read();
		 sum[i] = sum[i - 1] + p[i - 1] - d[i - 1];	
 	}
 	for(int i = n + 1;i <= 2 * n;++ i) 
 		sum[i] = sum[i - 1] + p[i - 1] - d[i - 1];
 	DP1();
 	for(int i = n * 2 ;i; -- i) 
		sum[i] = sum[i + 1] + p[i + 1] - d[i];
 	DP2();
 	for(int i = 1;i <= n;++ i) 
 		ok[i] ? puts("TAK") : puts("NIE");
 	return 0;
}  

10078. 「一本通 3.2 练习 4」新年好

简单题,spfa跑六边最短路,全排列枚举即可.

#include <iostream>
#include <cstring>
#include <queue>
#include <cstdio>
const int maxN = 5e4 + 7;
const int maxM = 1e5 + 7;
using namespace std;

int ke_dis[maxN][7];
queue <int>q;
bool vis[maxN];
int dis[maxN];

int Q[7],n,m; 

struct Node {
	int v,nex,w;
}Map[maxM << 1];
int head[maxN],num;

void add_Node(int u,int v,int w) {
	Map[++ num] = (Node) {v,head[u],w};
	head[u] = num;
	return ;
}

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

void spfa(int beg,int bh) {
	memset(dis,0x3f,sizeof(dis));
	dis[beg] = 0;
	q.push(beg);
	vis[beg] = true;
	while(!q.empty()) {
		int p = q.front();q.pop();vis[p] = false;
		for(int i = head[p];i;i = Map[i].nex) {
			int v = Map[i].v;
			if(dis[v] > dis[p] + Map[i].w) {
				dis[v] = dis[p] + Map[i].w ;
				if(!vis[v]) {
					q.push(v);
					vis[v] = true;
				}
			}
		}
	}
	for(int i = 1;i <= n;++ i) 
		ke_dis[i][bh] = dis[i];
	return;
}

long long ans;
bool is_ch[7];
int ch[7];//五个亲戚走的顺序 , 只是编号 Q[编号] 是车站的编号 
//特殊的Q[0] = 1 亲戚应该为1  

void work() {
	long long sum = 0;
	for(int i = 1;i <= 5;++ i) {
		sum += (long long) ke_dis[Q[ch[i - 1]]][ch[i]];
	}
	ans = min(ans,sum); 
} 

void dfs(int tot) {
	if(tot == 6) work();
	for(int i = 1;i <= 5;++ i) {
		if(!is_ch[i]) {
			ch[tot] = i;is_ch[i] = true;
			dfs(tot + 1);
			is_ch[i] = false;
		}
	}
}

int main() {
	n = read();m = read();
	Q[0] = 1;
	for(int i = 1;i <= 5;++ i)
		Q[i] = read();
	for(int i = 1,u,v,w;i <= m;++ i) {
		u = read();v = read();w = read();
		add_Node(u,v,w);	
		add_Node(v,u,w);
	}
	for(int i = 0;i <= 5;++ i) 
		spfa(Q[i],i);
	ans = 1e12;
	dfs(1);
	printf("%lld", ans);
	return 0;
}

#10220. 「一本通 6.5 例 2」Fibonacci 第 n 项

最简单的题目.
套一个矩阵乘法即可.

#include <iostream>
#include <cstring>
#include <cstdio>
#define ll long long
using namespace std;

struct Node {
	ll w[4][4];
	Node() {
		memset(w,0,sizeof(w));
	}
};
ll n,m;

Node mul(Node a,Node b) {
	Node c;
	for(ll i = 1;i <= 2;++ i) {
		for(ll j = 1;j <= 2;++ j) {
			for(ll k = 1;k <= 2;++ k) {
				c.w[i][j] = ( c.w[i][j] + a.w[i][k] * b.w[k][j] ) % m;
			}
		}
	}
	return c;
}

void fast_pow(ll b) {
	Node a,ans;
	a.w[1][1] = a.w[1][2] = a.w[2][1] = 1;
	ans.w[1][1] = ans.w[2][2] = 1;
	for(;b;b >>= 1,a = mul(a,a) ) {
		if(b & 1) ans = mul(ans,a);
	}
	Node tmp;
	tmp.w[1][1] = tmp.w[1][2] = 1;
	ans = mul(tmp,ans);
	printf("%lld", ans.w[1][1]);
	return ;
}

int main() {
	scanf("%lld%lld",&n,&m);
	if(n == 1) {puts("1");return 0;}
	if(n == 2) {puts("1");return 0;}
	fast_pow(n - 2);
	return 0;
}

考试收获

题目一定要读好,读准.
不然像这次, \(300 -> 220\)
暴力一定要打.
不然\(250\)分的暴力.
提高自己的码力和代码查错水平
现在,Gzy我现在要开始认真了呢.

posted @ 2018-10-10 19:42  Rlif  阅读(173)  评论(1编辑  收藏  举报