1.求表面积
题目描述:
将长N*M厘米的矩形区域划分成N行M列(每行每列的宽度均为1厘米),在第i行第j列的位置上叠放Ai,j个边长为1厘米的正方体(1≤Ai,j≤100),所有正方体就组成了一个立体图形,每个正方体六个面中的一部分会被其它正方体遮挡,未被遮挡的部分的总面积即为该立体图形的表面积,那么该立体图形的表面积是多少平方厘米?
输入:
第一行包含两个整数N和M,1≤N,M≤1000。
接下来N行,每行包含M个整数,第i行的第j个整数表示Ai,j。
输出:
输出表面积的大小。
样例:
输入:
2 2
2 1
1 1
输出:
20
思路:
把这个模型分成3个方向去看,前左上。其中从上看和从下看是一样的,也就是有方块的地方,顶和底就都+1。左前是有镂空的,用爬山下山的方式来数有多少个面:首先在这个输入矩阵的外围包上一圈0,如从前面看,就从前面的0开始往方块上走,比如样例第一列就是0 1 2 0,当平面抬高了,可认为出现了表面,就用后面的高度-前面的高度取绝对值,累加即可。
代码:
莫得代码
考试当天做出来了,AC
2.序列重组
两个数字,m进制,n位数,可以重新排序数字的顺序,两个数对应相加并对m取模而不进位,求最大和
题目描述:
在一个古老的国度,这个国家的人并不懂得进位,但是对取模情有独钟,因此诞生了一个经典的问题,给出两个在m进制下含有n位的数字,你可以分别将这两个数各位上的数字重新排列,然后将两个数按位对应相加并分别对m取模, 这样显然可以得到一个新的m进制下的n位数(可能存在前导0),但是这个结果是不唯一的,问题来了,按照这样的操作,能够得到的最大的m进制下的数字是多少呢。
输入:
输入第一行包含两个正整数n,m分别表示数字含有n位,和在m进制下。(n,m≤100000)
输入第二行和第三行分别包含n个整数,中间用空格隔开,每个整数都在0到m-1之间。每行第i个数表示的是当前数第i位上的数字。
输出:
输出包含n个数字,中间用空格隔开,表示得到的最大的数字,从高位到低位输出,如6在2进制下输出3位的结果是1 1 0。
样例:
输入:
5 5
4 4 1 1 1
4 3 0 1 2
输出:
4 4 3 3 2
解释:
4 4 1 1 1 →1 4 1 4 1
4 3 0 1 2 →3 0 2 4 1(重排序列不唯一,数位相加后的数字为 4 4 3 8 2,对5取模即可 )
思路:
链表+数组。
也就是尽量去构造加起来更大的数。用两个计数链表来存这两个数字池子里的数,如a[0]代表有a[0]个0,a[1]代表有a[1]个1…,b数组也一样,样例输入就可转换为 a[]={0,3,0,0,2} b[]={1,1,1,1,1}。由于结果上越前的数位上数字越大越好,所以用一个循环i从m-1往0跑,代表当前位上的相加结果,尝试去构造能加起来得到 i 的数字对。因为加起来能得到 i 的数对是固定的,如在样例中m为5,第一次循环时 i=4 ,加起来能得到4的数对只有(0,4)(1,3)(2,2)(3,1)(4,0),所以只要第一个数池里有1,第二个数池里有3,那就能配对,然后必然导致a[1]或者b[3]中小的那个变为0,大的那个变为 abs(a[1]-b[3]) ,计取得 min(a[1],b[3]) 个4,然后a[4]和b[0]也能在此配对,同理又取得 min(a[4],b[0]) 个4。这时候没有配对的了。在循环中当链表中有哪个数没有了,那就删掉那个节点,如a[]={0,3,0,0,2}就转变为a[]={3,2}。
循环往下走的时候,当 i 变到3,每个数的匹配关系从(0,4) (1,3) (2,2) (3,1) (4,0)变为(0,3) (1,2) (2,1) (3,0) (4,4),再次去找匹配对即可。
因为nm都是10万,所以估计上来说,一般就是扫一遍加上一个log,n²是肯定不行的,所以不能直接的去构造数对,要用权值链表来做,不然直接大模拟就好了。这样做看起来是O(M*N)的复杂度,但是由于链表在不停地减小,近似上来说内循环是一个log级别的复杂度,大概能过。
代码:
#include <cstdio>
using namespace std;
const int N = 110000;
struct Node
{
int Num,key,otherSide,next;
}node[2][N];
int head[2];
bool in[2][N];
int n,MOD;
int res[N];
void deleteNode(int last,int upOrDown)//删除某个节点的下一个节点,如果删头,输入-1
{
int now = node[upOrDown][ last ].next;
if(last == -1)
{
now = head[upOrDown];
if(node[upOrDown][ now ].next == -1)
{
head[upOrDown] = -1;
return ;
}
head[upOrDown] = node[upOrDown][now].next;
return;
}
node[upOrDown][last].next = node[upOrDown][now].next;
}
void clearList()
{
for(int i=0;i<=1;i++)
{
int now = head[i],last = -1;
while(now != -1)
{
if(node[i][now].Num <= 0)
{
in[i][now] = 0;
deleteNode(last,i);
now = last==-1?head[i]:node[i][last].next;
}
else
{
last = now;
now = node[i][now].next;
}
}
}
}
void list1Push_left()
{
int now = head[0],last = -1;
while(now != -1)
{
node[0][now].otherSide = node[0][now].otherSide==0 ? MOD-1 : node[0][now].otherSide-1;
now = node[0][now].next;
}
now = head[1],last = -1;
while(now != -1)
{
node[1][now].otherSide = node[1][now].otherSide==0 ? MOD-1 : node[1][now].otherSide-1;
now = node[1][now].next;
}
}
void showLinkList()
{
int temp = head[0];
printf("*****************输出链表*********************\n");
while(temp!=-1)
{
printf("i=%d Num=%d key=%d 对面=%d next=%d\n",temp,node[0][temp].Num,node[0][temp].key,node[0][temp].otherSide,node[0][temp].next);
temp = node[0][temp].next;
}
for(int i=0;i<MOD;i++)
if(in[0][i])printf("*");
else printf("_");
printf("\n");
printf("\n");
temp = head[1];
while(temp!=-1)
{
printf("i=%d Num=%d key=%d 对面=%d next=%d\n",temp,node[1][temp].Num,node[1][temp].key,node[1][temp].otherSide,node[1][temp].next);
temp = node[1][temp].next;
}
for(int i=0;i<MOD;i++)
if(in[1][i])printf("*");
else printf("_");
printf("\n");
printf("*****************结束*********************\n");
}
int main()
{
//初始化
scanf("%d%d",&n,&MOD);
for(int i=0;i<=MOD;i++)
node[0][i].Num = 0, node[0][i].next = i+1, node[0][i].otherSide = MOD-i-1, node[0][i].key = i;
node[0][MOD-1].next = -1;//-1代表链表结尾
head[0] = 0;
for(int i=MOD;i>=0;i--)
node[1][i].Num = 0, node[1][i].next = i-1, node[1][i].otherSide = MOD-i-1, node[1][i].key = i;
node[1][0].next = -1;
head[1] = MOD-1;
for(int i=0;i<=MOD;i++)
res[i] = 0,in[0][i] = 1,in[1][i] = 1;
int temp;
for(int i=1;i<=n;i++)
{
scanf("%d",&temp);
temp %= MOD;
node[0][temp].Num ++ ;
}
for(int i=1;i<=n;i++)
{
scanf("%d",&temp);
temp %= MOD;
node[1][temp].Num ++ ;
}
//启动
for(int m=MOD-1;m>=0;m--)
{
// printf("\n第%d轮,m为%d\n",MOD-m,m);
clearList();
// showLinkList();
int now = head[0],last;
while(now!=-1)
{
if(in[1][ node[0][now].otherSide ] != 0)
{
if(node[0][now].Num > node[1][ node[0][now].otherSide ].Num)
{
int temp = node[0][now].Num - node[1][ node[0][now].otherSide ].Num;
res[m] += node[1][ node[0][now].otherSide ].Num;
node[0][now].Num = temp;
node[1][ node[0][now].otherSide ].Num = 0;
}
else
{
int temp = node[1][ node[0][now].otherSide ].Num - node[0][now].Num;
res[m] += node[0][now].Num;
node[0][now].Num = 0;
node[1][ node[0][now].otherSide ].Num = temp;
}
if(node[0][now].Num == 0)
in[0][now] = 0;
if(node[1][ node[0][now].otherSide ].Num == 0)
in[1][ node[0][now].otherSide ] = 0;
}
now = node[0][now].next;
}
list1Push_left();
// showLinkList();
}
//输出结果
int pre0 = 0;//解决前导0判断符
for(int i=MOD-1;i>=0;i--)
{
if(res[i])
{
if(i>0)
{
for(int j=1;j<=res[i];j++)
printf("%d ",i);
pre0 = 1;
}
else if(pre0)
for(int j=1;j<=res[i];j++)
printf("%d ",i);
}
}
printf("\n");
return 0;
}
贼复杂啊,当天完全没做出来。现在做出来没有OJ,不知道对不对。测得几个数据倒是对了