2020上海高校程序设计竞赛暨第18届上海大学程序设计联赛夏季赛(同步赛)

本弱鸡还有三题没补~~~~~~

A 同源

题意:有三个整数a,b,c和一个目标值k
我们需要找满足gcd(a,b)=gcd(b,c)=gcd(a,c)=k
并且a,b,c不能等于k,其中a+b+c=n

问:是否存在满足条件的a,b,c,只需要输出一组,没有输出-1 -1 -1

分析:由于数据范围很大1e18,如果暴力枚举前2个数a,b,复杂度是n*n
这个复杂度明显不可以接收,然后我们需要剪枝,由于gcd都要是k,循环变量每次应该递增k,这样能加快一点。
最关键的一个剪枝是:当n%k如果不等于0时,说明还有剩余,那么是一定不可能存在的,直接输出-1 -1 -1.

详细请看代码:

#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstring>
#include <string>
#include <vector>
#include <map>
#include <queue>
#include <deque>
#include <set>
#include <stack>
#include <cctype>
#include <cmath>
#include <cassert>

#define IOS ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
#define INF 0x3f3f3f3f
#define PI 3.14159265358979323846

using namespace std;

typedef long long ll;

const ll mod=1000000007;
ll powmod(ll a,ll b) {ll res=1;a%=mod; assert(b>=0); for(;b;b>>=1){if(b&1)res=res*a%mod;a=a*a%mod;}return res;}
ll gcd(ll a,ll b) { return b?gcd(b,a%b):a;}

template<class T>inline void read(T &res)
{
	char c;T flag=1;
	while((c=getchar())<'0'||c>'9')if(c=='-')flag=-1;res=c-'0';
	while((c=getchar())>='0'&&c<='9')res=res*10+c-'0';res*=flag;
}

ll t;
ll n,k;

int main()
{
	scanf("%lld",&t);
	while(t--)
	{
		scanf("%lld%lld",&n,&k);
		
		//这里n%k不写, 会TLE 
		//case通过率为94.64%
		if(n%k)
		{
			printf("-1 -1 -1\n");
			continue;
		}
		
		
		bool f=false;
		for(ll i=2ll*k;i<=n-2ll*k;i+=k)
		{
			if(f)break;
			for(ll j=2ll*k;j<=i;j+=k)
			{
				ll z=n-i-j;
				if(z<=k||z<0)continue;
				if(gcd(i,j)==gcd(j,z)&&gcd(i,z)==k)
				{
					printf("%lld %lld %lld\n",i,j,z);
					f=true;
					break;
				}
			}
			if(f)break;
		}
		if(!f)printf("-1 -1 -1\n");
	}
	return 0;
}

B:分子

题意:给出有机分子C H O,对应 13,1,17的值。求有机化学式子的值。

分析:没有嵌套的括号,那么我只需要从头往后开始跑,用一个flag来标记当前计算的是括号里的还是在括号外的。 遇到左括号后,标记改变,说明接下来的值要单独算,因为是括号里的。然后我们要看后一个值是不是数字,如果是数字,我们就单独计算。 然后如果碰到右括号,flag标记改变,说明一组括号处理好了,但是也需要往后看看是不是有数字,因为括号外面可以加数字。

AC代码:

#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstring>
#include <string>
#include <vector>
#include <map>
#include <queue>
#include <deque>
#include <set>
#include <stack>
#include <cctype>
#include <cmath>
#include <cassert>

#define IOS ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
#define INF 0x3f3f3f3f
#define PI 3.14159265358979323846

using namespace std;

typedef long long ll;

const ll mod=1000000007;
ll powmod(ll a,ll b) {ll res=1;a%=mod; assert(b>=0); for(;b;b>>=1){if(b&1)res=res*a%mod;a=a*a%mod;}return res;}
ll gcd(ll a,ll b) { return b?gcd(b,a%b):a;}

template<class T>inline void read(T &res)
{
	char c;T flag=1;
	while((c=getchar())<'0'||c>'9')if(c=='-')flag=-1;res=c-'0';
	while((c=getchar())>='0'&&c<='9')res=res*10+c-'0';res*=flag;
}

const int N=1e5+100;

char s[N];

stack<char>sk;

ll zh(char c)
{
	if(c=='C')return 13;
	if(c=='H')return 1;
	if(c=='O')return 17;
	return 0; 
}

int main()
{
	scanf("%s",s+1);
	int len=strlen(s+1);
	ll sum=0;
	ll ans=0;
	bool f=false;
	for(int i=1;i<=len;i++)
	{
		char c=s[i];
		if(c=='(')
		{
			f=true;
			ans=0;
			continue;
		}
		ll num=1;
		if(i+1<=len&&isdigit(s[i+1]))
		{
			num=0;
			while(i+1<=len&&isdigit(s[i+1]))
			{
				num=num*10+(s[i+1]-'0');
				i++;
			}
		}
		if(!f)sum+=num*zh(c);
		else ans+=num*zh(c);
		
		if(c==')')
		{
			if(i+1<=len&&isdigit(s[i+1]))
			{
				num=0;
				while(i+1<=len&&isdigit(s[i+1]))
				{
					num=num*10+(s[i+1]-'0');
					i++;
				}
			}
			sum+=num*ans;
			ans=0;
			f=false;
		}
		//cout<<sum<<endl;
	} 
	printf("%lld\n",sum);
	return 0;
}

C 爵士

水体,直接做,如果是C++,需要会读一行。

AC代码:

#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstring>
#include <string>
#include <vector>
#include <map>
#include <queue>
#include <deque>
#include <set>
#include <stack>
#include <cctype>
#include <cmath>
#include <cassert>

#define IOS ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
#define INF 0x3f3f3f3f
#define PI 3.14159265358979323846

using namespace std;

typedef long long ll;

const ll mod=1000000007;
ll powmod(ll a,ll b) {ll res=1;a%=mod; assert(b>=0); for(;b;b>>=1){if(b&1)res=res*a%mod;a=a*a%mod;}return res;}
ll gcd(ll a,ll b) { return b?gcd(b,a%b):a;}

template<class T>inline void read(T &res)
{
	char c;T flag=1;
	while((c=getchar())<'0'||c>'9')if(c=='-')flag=-1;res=c-'0';
	while((c=getchar())>='0'&&c<='9')res=res*10+c-'0';res*=flag;
}

int t;
int n;
string s;

int main()
{
	IOS;
	cin>>t;
	while(t--)
	{
		cin>>n;
		cin.ignore();
		int c=0;
		for(int i=0;i<n;i++)
		{
			getline(cin,s);
			int pos=s.find("2");
			if(pos!=s.npos)c++;
		}
		double ans=c*1.0/n*1.0;
		printf("%.10f\n",ans);
	}
	return 0;
}

E 内存

题意:给出一张对应表,每次查询,给出一个十六进制数,要求把这个十六进制数先转换成二进制,然后取2部分,一个是前31-p个二进制数,一个是后p+1个二进制数,前31-p个二进制数转成十进制去表里映射,映射后再转成二进制,然后和后半部分拼接起来,再次转换成16进制,如果不能映射,就输出interrupt!

AC代码:

import java.util.Scanner;

public class Main
{

	public static void main(String[] args) 
	{
		Scanner sc=new Scanner(System.in);
		String z="00000000000000000000000000000000";
		while(sc.hasNext())
		{
			int n=sc.nextInt();
			int m=sc.nextInt();
			int p=sc.nextInt();
			int count=(int)Math.pow(2, m-p);
			int[]a=new int[count];
			for(int i=0;i<count;i++)
			{
				a[i]=sc.nextInt();
			}
			int q=sc.nextInt();
			while(q-->0)
			{
				String st=sc.next();
				Long shi=Long.valueOf(st, 16);
				String e=Long.toBinaryString(shi);
				//System.out.println(e);
				e=z.substring(e.length())+e;
				int first=Integer.valueOf(e.substring(0, e.length()-p), 2);
				
				//System.out.println(last);
				
				
				boolean f=false;
				for(int j=0;j<count;j++)
				{
					if(first==a[j])
					{
						f=true;
						first=j;
						break;
					}
				}
				
				String ss=Long.toBinaryString(first)+e.substring(e.length()-p);
				
				Long x=Long.valueOf(ss, 2);
				
				String sk=Long.toHexString(x);
				
				if(f==false)
				{
					System.out.println("interrupt!");
				}
				else
				{
					System.out.println(cal(sk));
				}
//				String two2=Integer.toBinaryString(last);
//				System.out.println(two+two2);
				
			}
		}

	}
	public static String cal(String s)
	{
		s=s.toUpperCase();
		while(s.length()<=7)
		{
			s="0"+s;
		}
		return s;
	}
	public static String add(String s,int num)
	{
		while(s.length()<num)
		{
			s="0"+s;
		}
		return s;
	}
}

F 游戏

题意:给出奇数个点,偶数条边的树,2者进行博弈。

分析:显然可以发现,先手必胜。

AC代码:

#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstring>
#include <string>
#include <vector>
#include <map>
#include <queue>
#include <deque>
#include <set>
#include <stack>
#include <cctype>
#include <cmath>
#include <cassert>

#define IOS ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
#define INF 0x3f3f3f3f
#define PI 3.14159265358979323846

using namespace std;

typedef long long ll;

const ll mod=1000000007;
ll powmod(ll a,ll b) {ll res=1;a%=mod; assert(b>=0); for(;b;b>>=1){if(b&1)res=res*a%mod;a=a*a%mod;}return res;}
ll gcd(ll a,ll b) { return b?gcd(b,a%b):a;}

template<class T>inline void read(T &res)
{
	char c;T flag=1;
	while((c=getchar())<'0'||c>'9')if(c=='-')flag=-1;res=c-'0';
	while((c=getchar())>='0'&&c<='9')res=res*10+c-'0';res*=flag;
}

int t;
int n;
int u,v;

int main()
{
	scanf("%d",&t);
	while(t--)
	{
		scanf("%d",&n);
		for(int i=0;i<n-1;i++)
		{
			scanf("%d%d",&u,&v);
		}
		printf("Yes\n");
	}
	return 0;
}

G 选择

题意:给出一个长度为n的数组,必须悬着n/2个数,并且不能相邻选,而且第x个数一定要选,问你拿走的最大值是多少。

分析:
第一眼看题,显然是一道dp题。

1、不考虑题目要求,我们会写一个二维dp,dp(i,j)表示前i个数选j个的最大值

2、由于题目n比较大,二维显然不可以,也可以发现,二维有很多状态都是没用的,比如dp[5][7]…

3、x点必须要选,那么在dp前,我们先给x这点的值,先加一个很大的值,这样的目的就是,在dp状态转移的时候,能把这个点选取。

4、然后我们可以发现,当第i项,i是偶数的时候,我们需要选i/2个数。
①当不选i这个点的时候,前i-1个数就要选i/2个数了。*可以发现如果前i-1个数要选i/2个数,又不能相邻,正好就是奇数项前缀和(也就是选一个隔一个,选一个隔一个)
② 当选i这个点的时候,第i-1的数就不能选了,所以是dp[i-2]+a[i]

if(i%2==0)
{
	dp[i]=max(sum[i-1],dp[i-2]+a[i]);
	//这里的sum数组存的是奇数项前缀和
}

5、i如果是奇数,dp方程就简单了。不选第i项,就是dp[i-1]
选第i项,就是dp[i-2]+a[i]

if(i%2==1)
{
	dp[i]=max(dp[i-1],dp[i-2]+a[i]);
	//这里的sum数组存的是奇数项前缀和
}

AC代码:

#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstring>
#include <string>
#include <vector>
#include <map>
#include <queue>
#include <deque>
#include <set>
#include <stack>
#include <cctype>
#include <cmath>
#include <cassert>

#define IOS ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
#define INF 0x3f3f3f3f
#define PI 3.14159265358979323846

using namespace std;

typedef long long ll;

const ll mod=1000000007;
ll powmod(ll a,ll b) {ll res=1;a%=mod; assert(b>=0); for(;b;b>>=1){if(b&1)res=res*a%mod;a=a*a%mod;}return res;}
ll gcd(ll a,ll b) { return b?gcd(b,a%b):a;}

template<class T>inline void read(T &res)
{
	char c;T flag=1;
	while((c=getchar())<'0'||c>'9')if(c=='-')flag=-1;res=c-'0';
	while((c=getchar())>='0'&&c<='9')res=res*10+c-'0';res*=flag;
}

const int N=200000+100;

ll n,x;

ll a[N];

ll sum[N];

ll dp[N];

int main()
{
	scanf("%lld%lld",&n,&x);
	for(ll i=1;i<=n;i++)
	{
		scanf("%lld",&a[i]);
	}
	
	//计算奇数项前缀和
	
	a[x]+=1e14;
	
	sum[1]=a[1];
	
	for(ll i=3;i<=n;i+=2)
	{
		sum[i]=sum[i-2]+a[i];
	} 
	
//	for(ll i=1;i<=n;i+=2)
//	{
//		printf("%lld ",sum[i]);
//	} 
//	printf("\n");
	
	
	for(ll i=2;i<=n;i++)
	{
		if(i%2==1)
		{
			dp[i]=max(dp[i-1],dp[i-2]+a[i]);
		}
		else
		{
			dp[i]=max(sum[i-1],dp[i-2]+a[i]);
		}
	}
	
//	for(ll i=1;i<=n;i++)
//	{
//		printf("%lld%c",dp[i]," \n"[i==n]);
//	}
	dp[n]-=1e14;
	printf("%lld\n",dp[n]);
	return 0;
}

有错请指出,如果有疑问,请私信!

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值