UPC2021级新生个人训练赛第31场

好久没总结了。主要是,之前那几场,大都不会,心态崩溃,摆烂还掉队。。

这次对了8道,有了点信心,最后2两道是后来借鉴大佬做法做出来的

问题 A: 幸运数字

签到题。。。

#include<iostream>
using namespace std;
typedef long long LL;
int main()
{
	LL n,ans=0;
	cin>>n;
	LL x;
	while(n--)
	{
		cin>>x;
		if(x%4==0||x%7==0)
		ans+=x;
	}
	cout<<ans;
	return 0;
}

问题 B: 对撞

这个题逻辑上也没啥难度,就是在实现的时候出了几次小错误。还有一开始看到数据范围以为要写高精就先跳过去了

#include<iostream>
#include<vector>
using namespace std;
typedef long long LL;
vector<int>x;
vector<int>y;
int main()
{
	string a,b;
	cin>>a>>b;
	int xa=0,xb=0;
	for(int i=0;i<a.length();i++)
	{
		if(a[i]==b[i])
		x.push_back(a[i]-'0'),y.push_back(b[i]-'0');
		else
		if(a[i]>b[i])
		x.push_back(a[i]-'0'),xa++;
		else
		y.push_back(b[i]-'0'),xb++;
	}
	if(xb<a.length())
	{
		int i=0;
		while(x[i]==0&&i<x.size())i++;
		if(i==x.size())cout<<0;
		for(;i<x.size();i++)
		cout<<x[i];
	}
	else
	cout<<"BOOM";
	cout<<endl;
	if(xa<a.length())
	{
		int i=0;
		while(y[i]==0&&i<y.size())i++;
		if(i==y.size())cout<<0;
		for(;i<y.size();i++)
		cout<<y[i];
	}
	else cout<<"BOOM\n";
	return 0;
}

问题 C: 差值求和

先排序,两两之间的绝对值可以用大的减小的,然后暴力,果断TLE。
找规律。。如果是5 1 2 3 4 5会怎么样ans= 5-4 + 5-3 +5-2 +5-1........+2-1最后一加和是4个5+2个4+0个3-2个2-4个1.然后这题就不会超时了

#include<iostream>
#include<algorithm>
using namespace std;
typedef long long LL;
LL n;
LL a[100005];
LL ans;
int main()
{
	cin>>n;
	for(int i=1;i<=n;i++)
	cin>>a[i];
	sort(a+1,a+1+n);
	int m=n-1;
	for(int i=n;i>0;i--,m-=2)
		ans+=(LL)a[i]*m;
	cout<<ans;
	return 0;
}

问题 D: 取数游戏

这个是我最后困扰的题,问题出在最后的每两个都要计算一下。TLE无解。。
赛后参照ytj大佬的代码,直呼妙啊~
这个的思路就是:从小到大排序,统计每个数字的个数,大于二的可以符合条件,可能的次数为个数*(个数-1).然后两两相乘,像C一样,暴力肯定会TLE
如何用O(n)实现O(n *n)的操作呢
这里我们是求和。假设有n个数两两相乘 a1,a2,...an ans=a1 *a2 +a1 *a3+.....+a1 *an +a2 *a3.......又可以反过来ans= an *a1+ an *a2+ ....+an * a(n-1)...+a(n-1) * a1........
发现没有 ?反过来后更好识别,ans就是2-n时 ai * sumi的和。这里问题就解决啦。

#include<iostream>
#include<map>
#include<algorithm>
#include<vector>
using namespace std;
typedef long long LL;
LL n,ans;
vector<int>a;
map<int,int>b;
int main()
{
	cin>>n;
	for(int i=0;i<n;i++)
	{
		int x;
		cin>>x;
		if(b[x]==0)
			a.push_back(x);
			b[x]++;
	}
	sort(a.begin(),a.end());
	for(int i=0;i<a.size();i++)
	{
		if(b[a[i]]==1)continue;
		b[a[i]]=b[a[i]]*(b[a[i]]-1)%1000000007;
	}
	LL sum=b[a[0]];
	for(int i=1;i<a.size();i++)
	{
		if(b[a[i]]==1)continue;
		ans+=sum*b[a[i]];
		sum+=b[a[i]];
		ans%=1000000007;
		sum%=1000000007;
	}
	cout<<ans;
	return 0;
}

问题 E: 哈夫曼编码

一开始以为要用到树相关的知识来,这些现在还不会,幸好这个题不是哈夫曼树,比较简单
统计,排序,基本操作

#include<iostream>
#include<map>
#include<algorithm>
using namespace std;
map<char,int>num;
struct letter
{
	char l;
	int su;
}A[30];
bool cmp(letter a,letter b)
{
	if(a.su>b.su)
	return 1;
	if(a.su==b.su)
	return a.l<b.l;
	if(a.su<b.su)
	return 0;
}
typedef long long LL;
string k;
int t=1;
int main()
{
	cin>>k;
	for(int i=0;i<k.length();i++)
	{
		if(num[k[i]]==0)
			num[k[i]]=t,t++;
		A[num[k[i]]].l=k[i];
		A[num[k[i]]].su++;
	}
	sort(A+1,A+t,cmp);
	for(int i=1;i<t;i++)
		cout<<A[i].l<<' '<<A[i].su<<endl;
	return 0;
}

问题 F: 智力大奖赛

emmm真就是一个找规律的题了,数列的一些知识不能忘。
小三角形是一个1 3 5 7 ......2 * n-1的一个等差数列 ans = n * n
能量棒我们可以只看横着的一条边1 2 3 4 5 6 ..... n的等差数列 ans = (n+1)n/2
最后别忘了 * 3

#include<iostream>
using namespace std;
typedef long long LL;
LL n;
int main()
{
	cin>>n;
	cout<<n*n<<endl;
	cout<<(1+n)*n/2*3;
	return 0;
}

问题 G: 求素数I

数据不大,直接暴力。
按照题意,挨个取,判断质数即可,然后经典的排序输出

#include<iostream>
#include<map>
#include<cmath>
#include<algorithm>
using namespace std;
typedef long long LL;
int n,l;
int a[101];
int b[101],t=0;
map<int,bool>h;
bool prime(int x)
{
	if(x<2)
	return 0;
	for(int i=2;i<sqrt(x);i++)
	if(x%i==0)
	return 0;
	return 1;
}
int main()
{
	cin>>n>>l;
	for(int i=1;i<=n;i++)
	cin>>a[i];
	for(int i=1;i<=n-l+1;i++)
	{
		int x=a[i];
		if(a[i]==0)continue;
		for(int j=i+1;j<i+l;j++)
		x=x*10+a[j];
		if(prime(x)&&(h[x]==0))
		{
			b[t]=x;
			h[x]=1;
			t++;
		}
	}
	sort(b,b+t);
	for(int i=0;i<t-1;i++)
	cout<<b[i]<<',';
	cout<<b[t-1];
	return 0;
}

问题 H: 立方和

这个题其实我还是有点疑问的。不过既然A了,也就问题不大了
递归解决即可,就是不符合条件至少走多少次令我困惑

#include<iostream>
using namespace std;
typedef long long LL;
int ans;
inline int po(int x)
{
	return x*x*x;
}
void work(int n,int l,int k)
{
	if(n==l)
	{
		ans=n;
		return;
	}
	if(k==999)return;
	n%=1000;
	work(po(n/100)+po(n/10%10)+po(n%10),n,k+1);
}
int main()
{
	int n;
	cin>>n;
	work(n,0,0);
	if(ans)
	cout<<ans;
	else cout<<"error";
	return 0;
}

what?学校网站又访问不了了??
凭印象写写吧

I:最大和最小

这个也类似数学吧。如果按照正常的运算顺序结果是最小的,如果先算加法再乘法,结果是最大的。我想到了,可是实现的时候失败了,后来赛后还是看的CSDN上一位大佬的才做出来。
数学证明咱没能力

#include<iostream>
#include<cctype>
using namespace std;
typedef long long LL;
char lk[101];
LL a[100],b[100],t=1;
int main()
{
	cin>>a[1];
	b[1]=a[1];
	while(cin>>lk[t])
	{
		if(lk[t]=='=')break;
		cin>>a[++t];
		b[t]=a[t];
	}
	LL x=0;
	LL k=1;
	for(int i=1;i<t;i++)
    {
        if(lk[i]=='*')
        {
            a[i+1]=a[i]*a[i+1];
            a[i]=0;
        }
        if(lk[i]=='+')
        {
            b[i+1]=b[i]+b[i+1];
            b[i]=1;
        }
    }
    for(int i=1;i<=t;i++)
    {
        x+=a[i];
        k*=b[i];
    }
	cout<<k<<endl;
	cout<<x;
	return 0;
}

J:电话

这村子摊上这个村长可真是倒霉到家了。什么癖好?
这个其实不难,按照序号排序,剩下和那个栅栏翻新就一样了。此处不多赘述

#include<iostream>
#include<algorithm>
using namespace std;
typedef long long LL;
LL n,m,ans;
struct tracker
{
	int s;
	int r;
}t[1000001];
bool cmp(tracker a,tracker b)
{
	return a.s<b.s;
}
int main()
{
	cin>>n>>m;
	for(int i=1;i<=n;i++)
	cin>>t[i].s>>t[i].r;
	sort(t+1,t+1+n,cmp);
	for(int i=1;i<=n;i++)
	if(t[i].r>t[i-1].r)ans+=(t[i].r-t[i-1].r);
	cout<<ans;
	return 0;
}

晚安

posted @ 2022-01-25 00:19  qbning  阅读(31)  评论(0编辑  收藏  举报
描述