这套题前部分略水,但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题
后缀数组还不会,题解也看不太懂。。明天继续连载。。。