BNU 25593 Prime Time 记忆化dp

题目链接:点击打开链接

题意:

一个游戏由3个人轮流玩

每局游戏由其中一名玩家选择一个数字作为开始

目的:获得最小的得分

对于当前玩家 O ,面对 u 这个数字

则他的操作有:

1、 计分 u +1 ,然后 u++;

2、计分 u / x, 然后 u /= x; 其中x为u的因子且x为素数

然后下一个玩家继续上述操作

3个人各操作一次 为1轮

当一轮结束后,若u==1 则游戏结束

每个人的得分为 他所有计分记录里最小的数字

若在一轮结束前 u就==1, 那么玩家的得分为本局游戏的初始数

求:

每个人在采取最优操作下玩n局游戏的总得分(不同局得分相加)

输入n表示n局游戏

下面n行给定 人名缩写+u

表示哪个玩家开始,他选择了哪个数字

思路:

1、n局游戏之间各不影响,所以分开考虑每局游戏

2、对于一局游戏,则我们可以记忆化搜索出每个数字u对应的状态

显然我们可以得到若u为素数时 答案就是 { 1, u, u}

若u不为素数,则u可以转移到状态v

在保证第一个数字最小的情况下,从越小的状态转移过来则结果越小

注意素数初始化时我们认为是{prime, inf, inf}  这样会得到一些不存在状态,而不存在的状态意义是本局游戏的初值

#include <stdio.h>
#include <algorithm>
#include<iostream>
#include<string.h>
#include <math.h>
#include<queue>
#include<map>
#include<vector>
#include<set>
using namespace std;
#define N 100008
#define inf 100000000
#define ll int
ll prime[9599], primenum;
set<int>s;
void PRIME(ll Max_Prime){
	primenum = 0;
	prime[primenum++] = 2;
	for(ll i = 3; i <= Max_Prime; i+= 2)
		for(ll j = 0; j < primenum; j++)
			if(i%prime[j]==0)break;
			else if(prime[j] > sqrt((double)i) || j==primenum-1)
			{
				prime[primenum++] = i;
				break;
			}
}
struct node{
	int a,b,c,ok;
	node(int x=0,int y=0,int z=0,int yes=0):a(x),b(y),c(z),ok(yes){}
}dp[N];
void dfs(int u){
	if(dp[u].ok)return;
	int t, fir = inf, id = inf;
	for(int i = 0; prime[i] <= u; i++)if(u % prime[i]==0) {
		dfs(u/prime[i]);
		t = min(u/prime[i], dp[u/prime[i]].c);
		if(t < fir || (t == fir && u/prime[i] < id))
			fir = t, id = u/prime[i];
	}
	dfs(u+1);
	t = min(u+1, dp[u+1].c);
	if(t < fir || (t == fir && u+1 < id))
		fir = t, id = u+1;
	dp[u] = node( fir, dp[id].a, dp[id].b, true);
}
int main(){
	int i, n;
	PRIME(100007);
	s.clear();
	for(i = 0; i < N; i++) dp[i].ok = false;
	for(i = 0; i < primenum; i++) {
		dp[prime[i]] = node(1, inf, inf, true);
		s.insert(prime[i]);
	}
	dp[1] = node(1, 1, 1, true);
	while(~scanf("%d",&n)){
		node ans = node(0, 0, 0, true);
		while(n--){
			char ch[2]; int u;
			scanf("%s %d", ch, &u);
			dfs(u);
			node tmp = dp[u];
			if(tmp.a == inf) tmp.a = u;
			if(tmp.b == inf) tmp.b = u;
			if(tmp.c == inf) tmp.c = u;

			if(ch[0] == 'O')
				ans.a += tmp.a, ans.b += tmp.b, ans.c += tmp.c;
			else if(ch[0] == 'E')
				ans.b += tmp.a, ans.c += tmp.b, ans.a += tmp.c;
			else
				ans.c += tmp.a, ans.a += tmp.b, ans.b += tmp.c;
		}
		printf("%d %d %d\n", ans.a,ans.b, ans.c);
	}
	return 0;
}

BNU 25593 Prime Time 记忆化dp

时间: 2024-10-05 16:43:50

BNU 25593 Prime Time 记忆化dp的相关文章

cf779D(记忆化dp)

题目链接: http://codeforces.com/problemset/problem/799/D 题意: 给出两个矩阵边长 a, b, 和 w, h, 以及一个 c 数组, 可选择 c 数组中任意数字乘上w 或 h. 数组中每个数字最多只能用一次. 求最少选择多少个数字可使得边长为 a, b 的矩阵能放到变化后的矩阵中. 思路: log2(1e5) = 17, 即最多需要对一条边乘17个数字, 要是完全暴力的话需要 2^34 的时间复杂度, 显然不行. 本题 dp 可解, 先给 c 降序

LightOJ 1038 Race to 1 Again 期望 记忆化dp

题目链接:点击打开链接 1038 - Race to 1 Again PDF (English) Statistics Forum Time Limit: 2 second(s) Memory Limit: 32 MB Rimi learned a new thing about integers, which is - any positive integer greater than 1 can be divided by its divisors. So, he is now playin

POJ 1088 滑雪(简单的记忆化dp)

题目 又一道可以称之为dp的题目,虽然看了别人的代码,但是我的代码写的还是很挫,,,,,, //看了题解做的简单的记忆化dp #include<stdio.h> #include<algorithm> #include<iostream> using namespace std; int mp[110][110],dp[110][110]; int xx[]={1,-1,0,0}; int yy[]={0,0,1,-1}; int n,m; int dfs(int x,

UVA - 11324 The Largest Clique 强连通缩点+记忆化dp

题目要求一个最大的弱联通图. 首先对于原图进行强连通缩点,得到新图,这个新图呈链状,类似树结构. 对新图进行记忆化dp,求一条权值最长的链,每个点的权值就是当前强连通分量点的个数. /* Tarjan算法求有向图的强连通分量set记录了强连通分量 Col记录了强连通分量的个数. */ #include <iostream> #include<cstring> #include<cstdio> #include<string> #include<algo

poj1692(区间记忆化dp)

题意:上下两行数相连,相等的才可以相连,并且每条线必须且只能与其他一条线相交(要同时满足相交的两条线的数不相等).问给的两行数最多可以连几条线. 解法:ans[i][j]记录着上面i,和下面j下标之后的数中最多可以连多少条,记忆化搜索dfs(0,0)就可以了.搜索时候,如果用到了i,则贪心在下面选相等的.用到j同理. 代码: /**************************************************** * author:xiefubao **************

Google Code Jam 2009, Round 1C C. Bribe the Prisoners (记忆化dp)

Problem In a kingdom there are prison cells (numbered 1 to P) built to form a straight line segment. Cells number i and i+1 are adjacent, and prisoners in adjacent cells are called "neighbours." A wall with a window separates adjacent cells, and

Codeforces Round #459 (Div. 2) C 思维,贪心 D 记忆化dp

Codeforces Round #459 (Div. 2) C. The Monster 题意:定义正确的括号串,是能够全部匹配的左右括号串. 给出一个字符串,有 (.). ? 三种字符, ? 可以当作 ( 可 ) . 问这个字符串有多少个子串是正确的括号串. tags:好考思维,想不到.. 预处理出每个字符向左向右最多可以匹配到哪里,再 O(n*n) 枚举所有区间,看是否符合条件. // C #include<bits/stdc++.h> using namespace std; #pra

uva11324 有向图的强连通分量+记忆化dp

给一张有向图G, 求一个结点数最大的结点集,使得该结点集中任意两个结点u和v满足,要么u可以到达v, 要么v可以到达u(u和v相互可达也可以). 因为整张图可能存在环路,所以不好使用dp直接做,先采用有向图的强连通分量,进行缩点,然后得到一个有向无环图(DAG) 在采用记忆话dp 去做即可 #include <iostream> #include <cstdio> #include <algorithm> #include <string.h> #inclu

UVA 1541 - To Bet or Not To Bet 记忆化DP概率

Alexander Charles McMillan loves to gamble, and during his last trip to the casino he ran across a new game. It is played on a linear sequence of squares as shown below. A chip is initially placed on the Start square. The player then tries to move th