一次不知道该叫什么的模拟赛和一篇不知道该起什么标题的补题

这套题前部分略水,但T2的正解(虽然A了),T5的优化,以及T6,在下都束手无策,还需要好好学习啊。。。。自己还是太水了。。。。

A题

模拟。。。直接贴代码了。。。、

#include<iostream>
#include<string.h>
#include<math.h>
#include<stdio.h>
#include<algorithm>
using namespace std;
int n;
string h;
int a[30],cnt=0;
int main()
{
	freopen("trener.in","r",stdin);
	freopen("trener.out","w",stdout);
	cin>>n;
	getchar();
	for(int i=1;i<=n;i++)
		cin>>h,a[h[0]-'a']++;
	for(int i=0;i<=25;i++)
		if(a[i]>=5)
			cout<<(char)(i+'a'),cnt++;
	if(cnt==0)
		cout<<"PREDAJA";
}

B题

n个人分m个蛋糕,求最小切刀数

啊啊啊其实正解很简单啊,从头到尾一个个模拟就好了,然而人比较笨虽然A了但就是死活想不到

        cin>>n>>m;
	for(int i=0;i<=n*m;i+=n) if(i%m!=0) ans++;
	cout<<ans<<endl;

本人做法挺离谱的,有递归做solve(n,m),n->当前剩的面包,m->要分的人

当n>=m时,说明每人吃超过1块面包,n=n%m;

当m>n时,处理此时应该把每个面包分成多少份x,和给每个人应发多少份y,先给x/y *n个人分够他们的量,那么m=m-x/y*n,同时ans+=x/y*n;

如果n=0,说明没有面包再分了,没必要做了,直接return;

如果m=0,说明没有人必要分了,但我还保留了这n块“空面包”,它们实际没必要被切,那么ans-=n;

是不是很严(fu)谨(za)啊。。。

#include<iostream>
#include<math.h>
#include<string.h>
#include<stdio.h>
#include<algorithm>
using namespace std;
int gcd(int a,int b)
{
	if(b==0)
		return a;
	return gcd(b,a%b);
}
int lcm(int a,int b)
{
	return a*b/gcd(max(a,b),min(a,b));
}
int ans,n,m,gong,mei,qie;
void jie(int n1,int m1)
{
	if(n1==0)
		return ;
	if(m1==0)
	{
		ans-=n1;
		return ;
	}
	if(n1>=m1)
	{
		int gong=lcm(n1,m1),qie=gong/n1,mei=gong/m1;
		int zhi=(mei/qie)*m1,yu=n1-zhi;
		jie(yu,m1);
	}
	else
	{
		int gong=lcm(n1,m1),qie=gong/n1,mei=gong/m1;
		ans+=qie/mei*n1;
		jie(n1,m1-qie/mei*n1);
	}
}
int main()
{
	freopen("kusac.in","r",stdin);
	freopen("kusac.out","w",stdout);	
	scanf("%d%d",&n,&m);
	jie(n,m);
	cout<<ans;
}

C题

给出一幅N*N的地图,每个格子上都有一个权值,求出有多少对矩形“对角”(即只有一个公共点)而且权值和相等。

先做一遍前缀和sum[i][j]表示从(1,1)到(i,j),那么我们就可以通过O(4)的复杂度求出任意一个矩形内的权值和。

枚举点(i,j)的右下点作为“对点”,先从(1,1)到(i,j)把所有以此为右下角的矩形都枚举一边,并把它们在对应值数组里个数+1,然后再枚举以这个点作为左上角的矩形们,并答案+=它在对应数组里的值,及这个值在左上方矩形(即以(i,j)为右下角的顶点的矩形们)出现过的次数,对与以(i,j)右上角,左下角的矩形做法也是同理。

注意在清空访问值次数时,不能直接memset,会很慢,应该在更新值出现次数时记录一下,最后清零时直接访问改即可。

#include<iostream>
#include<string.h>
#include<math.h>
#include<stdio.h>
#include<algorithm>
using namespace std;
int map[55][55],sum[55][55];
int in[5000050];
int g[2700];
int getsum(int x1,int y11,int x2,int y2)
{
	return sum[x2][y2]-sum[x2][y11-1]-sum[x1-1][y2]+sum[x1-1][y11-1];
}
int ans=0,n,gh[2555];
int main()
{
	freopen("ratar.in","r",stdin);
	freopen("ratar.out","w",stdout); 
	scanf("%d",&n);
	for(int i=1;i<=n;i++)
		for(int j=1;j<=n;j++)
			scanf("%d",&map[i][j]),sum[i][j]=map[i][j];
	for(int i=1;i<=n;i++)
		for(int j=1;j<=n;j++)
			sum[i][j]+=sum[i-1][j];
	for(int i=1;i<=n;i++)
		for(int j=1;j<=n;j++)
			sum[i][j]+=sum[i][j-1];
	for(int i=1;i<n;i++)
	{
		for(int j=1;j<n;j++)
		{
			int f,cnt=0;
			for(int i1=1;i1<=i;i1++)
				for(int j1=1;j1<=j;j1++)
					f=getsum(i1,j1,i,j)+2500000,in[f]++,gh[++cnt]=f;
			for(int i1=i+1;i1<=n;i1++)
				for(int j1=j+1;j1<=n;j1++)
					ans+=in[getsum(i+1,j+1,i1,j1)+2500000];
			for(int i1=1;i1<=cnt;i1++)
				in[gh[i1]]=0;
			cnt=0;
			for(int i1=i+1;i1<=n;i1++)
				for(int j1=1;j1<=j;j1++)
					f=getsum(i+1,j1,i1,j)+2500000,in[f]++,gh[++cnt]=f;
			for(int i1=1;i1<=i;i1++)
				for(int j1=j+1;j1<=n;j1++)
					ans+=in[getsum(i1,j+1,i,j1)+2500000];
			for(int i1=1;i1<=cnt;i1++)
				in[gh[i1]]=0;
		}
	}
	cout<<ans<<endl;
}


D题

一个很蠢的贼(而且还是被政府雇佣的。。。),他带了一堆包,都有容量,还有一堆珠宝,每个珠宝都有一定体积和一定价值,然而!!他只打算在每个包里只装一个珠宝。。。于是这道题从一个很好的背包问题变成了一个很蠢的贪心。。。

以一个结构体,存入所有的珠宝和背包,背包的价值设为-1以区别。按照容量按照小值sort一下,如果价值不为-1那么把这个值push进优先队列(最大值优先)里,如果是-1,

如果队列不为空,ans+=队首,并且将其出队。

#include<iostream>
#include<string.h>
#include<algorithm>
#include<stdio.h>
#include<math.h>
#include<queue>
#include<vector>
using namespace std;
priority_queue<int> q;
struct ba
{
	int v,room;
}bag[600500];
int cmp(ba a,ba b)
{
	return (a.room==b.room)?a.v>b.v:a.room<b.room;
}
int n,m;
long long ans;
int main()
{
	freopen("lopov.in","r",stdin);
	freopen("lopov.out","w",stdout);
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;i++)
		scanf("%d%d",&bag[i].room,&bag[i].v);
	for(int i=1;i<=m;i++)
		scanf("%d",&bag[i+n].room),bag[i+n].v=-1;
	sort(bag+1,bag+m+n+1,cmp);
	for(int i=1;i<=n+m;i++)
	{
		if(bag[i].v!=-1)
			q.push(bag[i].v);
		else
			if(!q.empty())
				ans+=q.top(),q.pop();
	}
	cout<<ans<<endl;
}

E题

给出一堆数,请计算i*(因数中含有I的数的个数)

我写的是裸的(做法是那种一读题就懂的),然而T了1个点。。。。

void init()
{
	for(int i=2;i<=2000000;i++)
	{
		if(prim[i]==0)
		for(int j=1;i*j<=2000000;j++)
		if(prim[i*j]==0) prim[i*j]=i;
	}
}
void get(int x)
{
    size=1;tmp[0]=1;
    while(x>1)
	{
        int p=prim[x];
        int pow=1;
        for(;x>1&&prim[x]==p;x/=p) pow++;
        for(int i=size;i<size*pow;i++) tmp[i]=tmp[i-size]*p;
        size*=pow;
    }   
}

加了马大佬的这个优化,就能过了。

他的这个算法复杂度小于o(根号n),思路是用prim[i]存i的第一个质因数,然后一直分解到j并将所有j的i倍数(得小于等于它含i的个数)一解决,紧接着再递归处理,并把他们的i倍加进去就好了。

F题

后缀数组还不会,题解也看不太懂。。明天继续连载。。。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值