2018 North Central North America 题解

Problem B Maximum Subarrays

Maximum Subarrays

题解:动态规划题,状态表示不是很好想,但状态转移感觉还行。
dp[i][j]:表示在加入第j个数字后,分成i段的最优解。
很容易想到,加入这个数,到底把它作为单独的一段还是和前面的一段合并,于是这两个状态就很容易去表示

  1. 作为单独的一段:必定由i-1段转移而来,(i-1)段至少加入(i-1)个数,所以我们取max(dp[i-1][i-1],dp[i-1][i]…dp[i-1][j-1])+a[j]。此时
    dp[i][j]=max(dp[i-1][i-1],dp[i-1][i]…dp[i-1][j-1])+a[j]
  2. 和前面的一段合并:由i段转移而来,要合并则必须和前一个数连续,所以只能由dp[i][j-1]转移而来。因此
    dp[i][j]=dp[i][j-1]+a[j]

易得状态转移方程:
dp[i][j]=max(dp[i][j-1]+a[j],max(dp[i-1][i-1],dp[i-1][i]…dp[i-1][j-1])+a[j]
发现dp只需当前状态和前一个状态的值,所以不妨用另外一个数组记录前一个状态最大值,这样就可以将二维数组减为一位数组。

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#define inf (1LL<<62)-1
using namespace std;
//extern "C"{void *__dso_handle=0;}
typedef long long ll;
typedef long double lb;
typedef pair<int, int> pii;
typedef unsigned long long ull;
const long double PI = acos(-1);
const int N = 5e3+10;
const int mod=998244353;

ll a[N],dp[N],maxx[N];
//dp[i][j] 
int main(int argc, char *argv[]) {
	int n,k;
	ll ans;
	cin >> n >> k;
	for(int i=1;i<=n;i++) scanf("%lld",&a[i]);
	for(int i=1;i<=k;i++)
	{
		ans=-inf;
		for(int j=i;j<=n;j++)
		{
			dp[j]=max(dp[j-1]+a[j],maxx[j-1]+a[j]);
			maxx[j-1]=ans;
			ans=max(ans,dp[j]);
		}
	}
	cout << ans << endl;
}

Problem C Rational Ratio

Rational Ratio

题解:本题有一个很关键的知识点,0.123123123…=123/999,知道了这个,模拟去做就行,但貌似我写复杂了,还是菜啊~~

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#define inf 0xffffff
using namespace std;
//extern "C"{void *__dso_handle=0;}
typedef long long ll;
typedef long double lb;
typedef pair<int, int> pii;
typedef unsigned long long ull;
const long double PI = acos(-1);
const int N = 5e6+10;
const int mod=998244353;

ll gcd(ll a,ll b) { return b==0? a : gcd(b,a%b); }
ll lcm(ll a,ll b) { return a*b/gcd(a,b); }
ll change(string s)
{
	stringstream ss;
	ss << s;
	ll ans;
	ss >> ans;
	return ans;
}
int main(int argc, char *argv[]) {
	string s;
	int a;
	cin >> s >> a;
	int cnt=0,flag=0,plen=0,id;
	for(int i=0;i<s.length();i++)
	{
		if(s[i]=='.')
		{
			flag=1;
			plen=s.length()-1-i;
		}
		if(flag)
		{
			if(cnt==plen-a)
			{
				id=i;
				break;
			}
			cnt++;
		}
	}
	string s1=s.substr(s.length()-plen,cnt),s2=s.substr(id+1,s.length()-1-id);
	string s3=s.substr(0,s.length()-1-plen);	
	ll inte=change(s3),dec=change(s2);
	ll up1,up2,down1,down2=0;
	if(s1=="")
	{
		up1=inte;
		down1=1;
	}
	else
	{
		int inte_dec=change(s1);
		up1=inte*pow(10, s1.length())+inte_dec;
		down1=pow(10, s1.length());
	}
	up2=dec;
	for(int i=0;i<s2.length();i++) down2=9*pow(10,i)+down2;
	down2*=pow(10,cnt);
	ll down=lcm(down1,down2);
	ll up=down/down1*up1+down/down2*up2;
	ll gg=gcd(up,down);
	up/=gg;
	down/=gg;
	printf("%lld/%lld\n",up,down);
}

Problem D Travel the Skies

题目: Travel the Skies

题面:给你k个飞机场,营业n天,有m个航班(出发地点、到达地点、出发时间、容量),n*k个时间点统计到飞机场的人数。
问是否每次航班能坐满,坐满则输出"optimal",否则"suboptimal".(如果必要可以把拉过去的人再拉回来。。O.O!)
题解:通过直接模拟来决这个问题。
用两个数组
b[i][j]:i机场第j天有多少人
a[i][j]:按照航班,i机场第j天能拉多少人。
对于每个机场每一天的航班进行模拟即可。

#include 

using namespace std;
int a[25][25],b[25][25];
bool optimal = true;
void solve()
{
	int k, n, m;
	cin >> k >> n >> m;
	for (int i = 0; i < m; ++i) {
		int from, to, day, cap;
		cin >> from >> to >> day >> cap;
		a[from][day] += cap;
		if (day + 1 <= n) b[to][day + 1] += cap;
	}
	for (int i = 0; i < k * n; ++i) {
		int airport, day, num_people;
		cin >> airport >> day >> num_people;
		b[airport][day] += num_people;
	}
	
	for (int i = 1; i<=k; ++i) {
		int now = 0;
		for (int j = 1; j<=n; ++j) {
			now += b[i][j];
			if (now < a[i][j]) {
				optimal = false;
				return ;
			}
			now -= a[i][j];
		}
	}
}
int main() {
	solve();
	cout << (optimal ? "optimal" : "suboptimal") << endl;
}

Problem E Euler’s Number

题目: Euler’s Number

n大于一定值就不会改变。

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#define inf 0xffffff
using namespace std;
//extern "C"{void *__dso_handle=0;}
typedef long long ll;
typedef long double lb;
typedef pair<int, int> pii;
typedef unsigned long long ull;
const long double PI = acos(-1);
const int N = 5e6+10;
const int mod=998244353;

lb f[10005];
void init()
{
	f[0]=1;
	for(int i=1;i<=100;i++)
		f[i]=i*f[i-1];
}
int main(int argc, char *argv[]) {
	init();
	int n;
	cin >> n;
	lb ans=1;
	if(n<=20)
	{
		for(int i=1;i<=n;i++)
		{
			ans+=1.0/f[i];
		}
		printf("%.15Lf",ans);
	}
	else cout << "2.718281828459045" << endl;
}

Problem F Lipschitz Constant

题目: Lipschitz Constant

题解:题意可以理解为从点集合中找两点使得斜率最大,很容易想到斜率最大的两个点必定是连续的,所以按照x大小排序后,遍历两个连续点的斜率,取最大值即可。

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#define inf 0xffffff
using namespace std;
//extern "C"{void *__dso_handle=0;}
typedef long long ll;
typedef long double lb;
typedef pair<int, int> pii;
typedef unsigned long long ull;
const long double PI = acos(-1);
const int N = 5e6+10;
const int mod=998244353;

struct Node
{
	double x,y;
}node[200005];
bool cmp(struct Node a,struct Node b)
{
	return a.x < b.x;
}
int main(int argc, char *argv[]) {
	int n;
	cin >> n;
	for(int i=0;i<n;i++)
		cin >> node[i].x >> node[i].y;
	sort(node,node+n,cmp);
	lb ans=-1;
	for(int i=1;i<n;i++)
	{
		lb tmp=fabs((node[i].y-node[i-1].y)/(node[i].x-node[i-1].x));
		ans=max(ans,tmp);
	}
	printf("%.9Lf",ans);
}

Problem I Other Side

Other Side

题解:狼吃羊,羊吃草的经典问题
可以说是思维题
船的容量为k,从题中可知

  1. 当k>min(w+c,s)时,必定有解,因为一开始你就必须把狼和草或者羊运走分开,否则就会被吃。
  2. 当k==min(w+c,s)时,得看情况,首先肯定是把min(w+c,s)运到河岸对面,剩下的就是max(w+c,s),然后你又把max(w+c,s)里的k运到对面,此时为了防止被吃,你需要把第一次遇到对面的min(w+c,s)再拉过来,此时,河这边有两部分:第一次的min(w+c,s)和第二次没运完剩下的max(w+c,s)-k,同时河对岸还有第二次运的k,此时你必须把第二次没运完剩下的max(w+c,s)-k运过去,那么此时要求k≥max(w+c,s)-k才能满足条件。
    综上所述:k=min(w+c,s)时,2*k≥max(w+c,s)才会有解
  3. 剩下的当然就是没解的啦。
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#define inf 0xffffff
using namespace std;
//extern "C"{void *__dso_handle=0;}
typedef long long ll;
typedef long double lb;
typedef pair<int, int> pii;
typedef unsigned long long ull;
const long double PI = acos(-1);
const int N = 5e6+10;
const int mod=998244353;

int main(int argc, char *argv[]) {
	int w,s,c,k;
	cin >> w >> s >> c >> k;
	if(k>min(s,w+c)) cout << "YES" << endl;
	else if(k==min(s,w+c) && k>=max(s, w+c)) cout << "YES" << endl;
	else cout << "NO" << endl;
}

Problem J Kaleidoscopic Palindromes

Kaleidoscopic Palindromes

题解:暴力出奇迹!

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#define inf 0xffffff
using namespace std;
//extern "C"{void *__dso_handle=0;}
typedef long long ll;
typedef long double lb;
typedef pair<int, int> pii;
typedef unsigned long long ull;
const long double PI = acos(-1);
const int N = 5e6+10;
const int mod=998244353;

int a[50];
bool judge(int num,int k)
{
	int cnt=0;
	while (num) {
		a[cnt++]=num%k;
		num/=k;
	}
	cnt--;
	for(int i=0;i<=cnt/2;i++)
	{
		if(a[i]!=a[cnt-i]) return false;
	}
	return true;
}
int main(int argc, char *argv[]) {
	int a,b,k;
	cin >> a >> b >> k;
	int ans=0;
	for(int i=a;i<=b;i++)
	{
		int base=2;
		for(;base<=k;base++)
		{
			if(!judge(i,base)) break;
		}
		if(base==k+1) ans++;
	}
	cout << ans ;
}

你可能感兴趣的:(2018 North Central North America 题解)