UPC 2020年夏混合个人训练第七十九场

问题 A: Prime

题目描述
任何大于 1 的自然数 N,都可以写成若干个大于等于2且小于等于 N 的质数之和表达式(包括只有一个数构成的和表达式的情况),并且可能有不止一种质数和的形式。例如9 的质数和表达式就有四种本质不同的形式:9 = 2+5+2 = 2+3+2+2 = 3+3+3 = 2+7 。
这里所谓两个本质相同的表达式是指可以通过交换其中一个表达式中参加和运算的各个数的位置而直接得到另一个表达式。
试编程求解自然数 N 可以写成多少种本质不同的质数和表达式。

输入
一个自然数 N , 2≤N≤2000。
输出
输出每一个自然数 N 的本质不同的质数和表达式的数目。
样例输入
2
样例输出
1

题解:这是一个套完全背包模板的题——质数和分解。先筛出2000内所有素数,作为元素来塞背包,看最后有多少塞法。答案会爆unsigned long long,于是使用高精度。

#include <bits/stdc++.h> 
#define PRIMEL 2001
#define ULL unsigned long long
bool vis[PRIMEL];
int prime[PRIMEL],tot=1;

inline int max(int a,int b){
    
    
    return a>b ? a:b;
}

void phi(){
    
    
    int tmp=(PRIMEL+1)/2;
    for(int i=2;i<=tmp;i++)
        if(!vis[i])
		    for(int j=i+i; j<PRIMEL; j+=i)  vis[j]=true;
    for(int i=2;i<PRIMEL;i++)
        if(!vis[i])  prime[tot++]=i;
}
 
struct Num{
    
    
    char s[100];
    int len;
    Num(){
    
    len=0;memset(s,0,sizeof s);}
    Num(const Num&a){
    
    
        memcpy(s,a.s,sizeof s);
        len=a.len;
    }
    void print(){
    
    
        for(int i=len-1; i>=0; i--)    putchar(s[i]+'0');
    }
};

Num operator+(Num a,Num b)
{
    
    
    Num ret;
    int len = max(b.len,a.len);
    for(int i=0; i<len; i++){
    
    
        ret.s[i] += a.s[i]+b.s[i];
        ret.s[i+1] = ret.s[i]/10;
        ret.s[i] %= 10;
    }
    if(ret.s[len])len++;
    ret.len=len;
    return ret;
}
 
int n;
Num f[2001];

int main()
{
    
    
    f[0].len=1;
    f[0].s[0]=1;
    phi();
    scanf("%d",&n);
    for(int i=1; i<tot&&prime[i]<=n; i++)
        for(int j=prime[i]; j<=n; j++)
            f[j] = f[j-prime[i]]+f[j];
    f[n].print();
}

问题 C: Inflate

题目描述
设计一次竞赛使得选手最大可能的得分尽可能高。可供选择的题目共有N类(1 <= N <= 10,000),你可以从每一类题目中选出任意道题或不选组成一次竞赛。某一类题中的每一道题都需要相同的时间并能得到相同的分数。竞赛总时间不超过M分钟(1 <= M <= 10,000)。

输入
第一行两个整数M, N分别表示竞赛总时间与题目类数;第2到N+1行每行两个整数,分别表示这类题每一道的分数和所需时间。
输出
仅一行,即给定条件下最大可能的得分。
样例输入
300 4
100 60
250 120
120 100
35 20
样例输出
605

这是一个背包问题的模板例题

#include <bits/stdc++.h> 
using namespace std;
#define MAXN 10002
#define MAX(a,b) a>b?a:b
 
int M;			//竞赛总时间 
int N;			//竞赛题的类别数 
int s[MAXN];  //题i的分数 
int t[MAXN];  //题i所需的时间 
int f[MAXN];   
	
int main()
{
    
    
	scanf("%d%d",&M,&N);
	for(int i=1; i<=N; i++)
		scanf("%d%d",&s[i],&t[i]);
		
	memset(f,0,sizeof(f));
	
	for(int i=1; i<=N; i++)
		for(int j=0; j<=M; j++)
		{
    
    
			if(j<t[i])  f[j]=f[j];
			else  f[j] = MAX(f[j], f[j-t[i]]+s[i]);
		}
			
	printf("%d\n",f[M]);
	return 0;
} 

问题 D: 密码 password

题目描述
为什么这么多人要把密码设成 123456 啊?这给我很多机惨的机会。—— LinZhengyu
机房的很多人把电脑密码设成 123456 ,导致了许多机房惨案。
LinZhengyu 调查了许多人,调查表明在一个人心中, 123456 这六个数分别代表了一个字符串,只要把这些串顺次连接,就可以破解密码。
LinZhengyu 又调查一位可怜人,他想请 花生 把密码破解出来。
但 花生 不愿意干这种事,于是他找到了聪明优秀的你。

输入
共 6 行,每行有一个数字 n 和一个字符串S,表示数字n代表的字符串是S。
输出
输出这个密码。
样例输入
【样例1】
1 Tweetuzki
2 s
3 password
4 i
5 s
6 123456
【样例2】
2 Zhengyu
5 dalao
3 is
6 .
1 Lin
4 a
样例输出 Copy
【样例1】
Tweetuzkispasswordis123456
【样例2】
LinZhengyuisadalao.

题解:建立一个结构体, 有编号, 和字符串,两个变量。 然后根据编号升序排个序,按顺序输出即可。也可以排序后,顺序链接字符串,用string的话,可以直接 s1 += s2。char[ ]的话可以每次用stract,最后1次输出。

#include <bits/stdc++.h> 
using namespace std;
string s,s1;

struct qwq{
    
    
	int a;	//编号
	string s;  //字符串
}p[7];

bool cmp(qwq x,qwq y){
    
    
	return x.a<y.a;
}

int main()
{
    
    	
    for(int i=0; i<6; i++)
        cin>>p[i].a>>p[i].s;
    sort(p,p+6,cmp);    
    for(int i=0; i<6; i++) cout<<p[i].s;
    return 0;
}

问题 E: 环绕膜拜 round

题目描述
XXX 大学霸,巨啊! —— 福州时代中学 2019 届名言
学长们非常喜欢把一个人环绕起来膜,比如 谢队 。
现在把机房抽象成平面直角坐标系,共有 n 个人,第 i 个人的坐标是 (xi,yi)
一个定义平面上的一个点为黄金被膜点,当且仅当可以把 n 个点分成 n/2 对,每组的两个点连成的线段的中点都是这个点。
现在机房的人想找到这个黄金被膜点,方便 谢队 来的时候膜他。
花生 被安排找到这个黄金被膜点,可是他比较蠢,于是他来求助你。

输入
共 n+1 行。
第 1 行有一个正偶数 n ,表示机房的人数。
接下来 n 行,每行两个整数xi,yi ,表示第 i 个人所在的位置。
输出
若可以找到这个黄金被膜点,那么输出两个整数(保证其是整点),表示这个黄金被膜点的坐标;若无法找到这个点,则输出 There is not a place like that. 。

样例输入
【样例1】
8
1 10
3 6
6 8
6 2
3 -4
1 0
-2 -2
-2 4
【样例2】
8
1 100
3 6
6 8
6 2
3 -4
1 0
-2 -2
-2 4
样例输出
【样例1】
2 3
【样例2】
There is not a place like that.

提示
在这里插入图片描述
题解:这题要利用中心的性质来写,能够找到这个点时,每一组 的中心点 等价于 所有点的中心点,找不到这个中心点时特判。

#include <bits/stdc++.h> 
#define ll long long 
using namespace std;
const int N = 1e6+10;

int n,a[N],b[N];
ll sum1,sum2;

int main()
{
    
    
    cin>>n;
    for(int i=0; i<n; i++)
	{
    
    
        cin>>a[i]>>b[i];
        sum1 += a[i];
        sum2 += b[i];
    }
     
    if(sum1&1 || sum1%n || sum2&1 || sum2%n) {
    
     
        // 是奇数或者不能整除时,找不到那个中心点
        /* &注意一下, 有时候运算优先级会出错,尽量遇到用 & ^ 的都用一下括号*/
        cout << "There is not a place like that." << endl;
        return 0;
    }
     
    int x = sum1/n, y = sum2/n;
    cout<<x<<' '<<y<<endl; 
    return 0;
}

猜你喜欢

转载自blog.csdn.net/Luoxiaobaia/article/details/108028405
UPC