2017CCCC天梯赛决赛 赛后总结

稍微刷了几道题,所以果然还是做崩了。




账号hdhd1_hdu0_s3_8  密码a80d46

拿了252分,总排名算第16名?手速还是不够,依旧被csy虐惨了233333。


前期开错了题,先做的L2-004,速度不够,大概10~20个才做完。

然后发现L3没人AC,于是立马转战L3-001,做完还是10~20名的样子。

感觉一开始直接冲L3就好了>.<


接下来把L1水过去了。做L1-6的时候SB了,亏了5分,先回顾下这道题……


https://www.patest.cn/contests/2017gplt-2/L1-6

L1-6. 这道就算难题吧

时间限制
400 ms
内存限制
65536 kB
代码长度限制
8000 B
判题程序
Standard
作者
翁恺

这里所谓的“光棍”,并不是指单身汪啦~ 说的是全部由1组成的数字,比如1、11、111、1111等。传说任何一个光棍都能被一个不以5结尾的奇数整除。比如,111111就可以被13整除。 现在,你的程序要读入一个整数x,这个整数一定是奇数并且不以5结尾。然后,经过计算,输出两个数字:第一个数字s,表示x乘以s是一个光棍,第二个数字n是这个光棍的位数。这样的解当然不是唯一的,题目要求你输出最小的解。

提示:一个显然的办法是逐渐增加光棍的位数,直到可以整除x为止。但难点在于,s可能是个非常大的数 —— 比如,程序输入31,那么就输出3584229390681和15,因为31乘以3584229390681的结果是111111111111111,一共15个1。

输入格式:

输入在一行中给出一个不以5结尾的正奇数x(< 1000)。

输出格式:

在一行中输出相应的最小的s和n,其间以1个空格分隔。

输入样例:
31
输出样例:
3584229390681 15



用Java写当然很方便啊!结果忘记Java的入口了,就是这个——

public class Main
{
	public static void main(String[] args)
	{
		Scanner cin = new Scanner(System.in);
	}
}


忘记这个怎么写了,eclipse试了一会,没试出来就GG了>.<  没想到考大数,唉>.<!
然而这道题一个更高效得多的做法是手动模拟高精除单精。比赛的时候懵逼了,自己强行把这个做法ban掉了。有点可惜啊233333


int n;
char ans[N];
int main()
{
	while(~scanf("%d", &n))
	//for(int n = 1; n <= 1000; ++n)if(n % 2 == 1 && n % 10 != 5)
	{
		int p = 0;
		int now = 1;
		for (int len = 1; ; ++len)
		{
			if(p || now / n)ans[p++] = '0' + now / n;
			now %= n;
			if (now == 0)
			{
				ans[p] = 0;
				printf("%s %d\n", ans, len);
				break;
			}
			now = now * 10 + 1;
		}
	}
	return 0;
}

然后【2017CCCC团体程序设计天梯赛】【链表模拟】L2-2 重排链表

我把while (l <= r) 写成 while(l < r)了,难过!错过了3分。

#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
void fre() { freopen("c://test//input.in", "r", stdin); freopen("c://test//output.out", "w", stdout); }
#define MS(x, y) memset(x, y, sizeof(x))
#define ls o<<1
#define rs o<<1|1
typedef long long LL;
typedef unsigned long long UL;
typedef unsigned int UI;
template inline void gmax(T1 &a, T2 b) { if (b > a)a = b; }
template inline void gmin(T1 &a, T2 b) { if (b < a)a = b; }
const int N = 1e5 + 10, M = N * N * 2, Z = 1e9 + 7, inf = 0x3f3f3f3f;
template inline void gadd(T1 &a, T2 b) { a = (a + b) % Z; }
int casenum, casei;
int H, n;
int v[N];
int nxt[N];
int a[N], b[N];

int g;
void dfs(int x)
{
	if (x == -1)return;
	a[++g] = x;
	dfs(nxt[x]);
}
int main()
{
	while (~scanf("%d%d", &H, &n))
	{
		for (int i = 1; i <= n; ++i)
		{
			int x, val, y;
			scanf("%d%d%d", &x, &val, &y);
			v[x] = val;
			nxt[x] = y;
		}

		g = 0; dfs(H);
		int m = 0;
		int r = g;
		int l = 1;
		while (l <= r)
		{
			b[++m] = a[r--];
			if (l > r)break;
			b[++m] = a[l++];
		}b[m + 1] = -1;
		for (int i = 1; i < m; ++i)
		{
			printf("%05d %d %05d\n", b[i], v[b[i]], b[i + 1]);
		}
		int i = m; printf("%05d %d -1\n", b[i], v[b[i]]);
	}
	return 0;
}


然后接下来就是最后2题啦——

【2017CCCC团体程序设计天梯赛】【贪心+线段树】L3-2 森森快递

这题直接按照不相覆盖的区间做贪心,依次枚举,然后使用线段树更新就好啦~~ 很快就1A了。

#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
void fre() { freopen("c://test//input.in", "r", stdin); freopen("c://test//output.out", "w", stdout); }
#define MS(x, y) memset(x, y, sizeof(x))
#define rt 1,1,n
#define ls o<<1
#define rs o<<1|1
#define mid (l+r>>1)
#define lson o<<1,l,mid
#define rson o<<1|1,mid+1,r
typedef long long LL;
typedef unsigned long long UL;
typedef unsigned int UI;
template inline void gmax(T1 &a, T2 b) { if (b > a)a = b; }
template inline void gmin(T1 &a, T2 b) { if (b < a)a = b; }
const int N = 4e5 + 10, M = N * N * 2, Z = 1e9 + 7, inf = 0x3f3f3f3f;
template inline void gadd(T1 &a, T2 b) { a = (a + b) % Z; }
int casenum, casei;
int n, m;
LL flag[N];
LL mn[N];
void pushup(int o)
{
    mn[o] = min(mn[ls], mn[rs]);
}
void pushdown(int o)
{
    if(flag[o])
    {
        mn[ls] -= flag[o]; flag[ls] += flag[o];
        mn[rs] -= flag[o]; flag[rs] += flag[o];
        flag[o] = 0;
    }
}
void build(int o, int l, int r)
{
    flag[o] = 0;
    if(l == r)
    {
        scanf("%lld", &mn[o]);
        return;
    }
    build(lson);
    build(rson);
    pushup(o);
}
struct A
{
    int first, second;
    bool operator < (const A & b)const
    {
        if(first != b.first)return first < b.first;
        return second > b.second;
    }
}a[N], b[N];

LL L, R, V;
LL check(int o, int l, int r)
{
    if(L <= l && r <= R)return mn[o];
    LL ret = 1e18;
    pushdown(o);
    if(L <= mid)gmin(ret, check(lson));
    if(R > mid)gmin(ret, check(rson));
    return ret;
}
void modify(int o, int l, int r)
{
    if(L <= l && r <= R)
    {
        mn[o] -= V;
        flag[o] += V;
        return;
    }
    pushdown(o);
    if(L <= mid)modify(lson);
    if(R > mid)modify(rson);
    pushup(o);
}
int main()
{
    while(~scanf("%d%d", &n, &m))
    {
        --n; build(1, 1, n);
        for(int i = 1; i <= m; ++i)
        {
            int x, y;scanf("%d%d", &x, &y);
            if(x > y)swap(x, y); ++x;
            a[i] = {x, y};
        }
        sort(a + 1, a + m + 1);

        int g = 0;
        for(int i = 1; i <= m; ++i)
        {
            while(g && a[i].first >= b[g].first && a[i].second <= b[g].second)--g;
            b[++g] = a[i];
        }

        LL ans = 0;
        for(int i = 1; i <= g; ++i)
        {
            L = b[i].first;
            R = b[i].second;
            V = check(rt);
            modify(rt);
            ans += V;
        }
        printf("%lld\n", ans);
    }
    return 0;
}


最后一题实在是因为时间不多了。其实就是很基础的最短路。所以说也许拼一拼时间,争取多A个题,还是很有必要的。

L3-3. 森森美图

时间限制
400 ms
内存限制
65536 kB
代码长度限制
8000 B
判题程序
Standard
作者
戴龙翱、朱建科

森森最近想让自己的朋友圈熠熠生辉,所以他决定自己写个美化照片的软件,并起名为森森美图。众所周知,在合照中美化自己的面部而不美化合照者的面部是让自己占据朋友圈高点的绝好方法,因此森森美图里当然得有这个功能。 这个功能的第一步是将自己的面部选中。森森首先计算出了一个图像中所有像素点与周围点的相似程度的分数,分数越低表示某个像素点越“像”一个轮廓边缘上的点。 森森认为,任意连续像素点的得分之和越低,表示它们组成的曲线和轮廓边缘的重合程度越高。为了选择出一个完整的面部,森森决定让用户选择面部上的两个像素点A和B,则连接这两个点的直线就将图像分为两部分,然后在这两部分中分别寻找一条从A到B且与轮廓重合程度最高的曲线,就可以拼出用户的面部了。 然而森森计算出来得分矩阵后,突然发现自己不知道怎么找到这两条曲线了,你能帮森森当上朋友圈的小王子吗?

为了解题方便,我们做出以下补充说明:

  • 图像的左上角是坐标原点(0,0),我们假设所有像素按矩阵格式排列,其坐标均为非负整数(即横轴向右为正,纵轴向下为正)。
  • 忽略正好位于连接A和B的直线(注意不是线段)上的像素点,即不认为这部分像素点在任何一个划分部分上,因此曲线也不能经过这部分像素点。
  • 曲线是八连通的(即任一像素点可与其周围的8个像素连通),但为了计算准确,某像素连接对角相邻的斜向像素时,得分额外增加两个像素分数和的根号2倍减一。例如样例中,经过坐标为(3,1)和(4,2)的两个像素点的曲线,其得分应该是这两个像素点的分数和(2+2),再加上额外的(2+2)乘于(根号2减一),即约为5.66。

输入格式:

输入在第一行给出两个正整数N和M(5 <= N, M <= 100),表示像素得分矩阵的行数和列数。

接下来N行,每行M个不大于1000的非负整数,即为像素点的分值。

最后一行给出用户选择的起始和结束像素点的坐标(Xstart, Ystart)和(Xend, Yend)。4个整数用空格分隔。

输出格式:

在一行中输出划分图片后找到的轮廓曲线的得分和,保留小数点后两位。注意起点和终点的得分不要重复计算。

输入样例:
6 6
9 0 1 9 9 9
9 9 1 2 2 9
9 9 2 0 2 9
9 9 1 1 2 9
9 9 3 3 1 1
9 9 9 9 9 9
2 1 5 4
输出样例:
27.04

#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
void fre() { freopen("c://test//input.in", "r", stdin); freopen("c://test//output.out", "w", stdout); }
#define MS(x, y) memset(x, y, sizeof(x))
#define ls o<<1
#define rs o<<1|1
typedef long long LL;
typedef unsigned long long UL;
typedef unsigned int UI;
template inline void gmax(T1 &a, T2 b) { if (b > a)a = b; }
template inline void gmin(T1 &a, T2 b) { if (b < a)a = b; }
const int N = 105, M = 0, Z = 1e9 + 7, inf = 0x3f3f3f3f;
template inline void gadd(T1 &a, T2 b) { a = (a + b) % Z; }
int casenum, casei;
int n, m;
int a[N][N];

struct Point
{
	int y, x;
	bool operator != (const Point &b)const
	{
		return x != b.x || y != b.y;
	}
}p0, p1;

//基础函数,判定p2相对于(p0->p1)的方向:①正,p2在p1的逆时针向;②负,则p2在p1的顺时针向;③零,共线
LL cp(Point p0, Point p1, Point p2)
{
	LL x1 = p1.x - p0.x;
	LL y1 = p1.y - p0.y;
	LL x2 = p2.x - p0.x;
	LL y2 = p2.y - p0.y;
	return x1 * y2 - x2 * y1;
}

struct Node
{
	Point p; double dis;
	bool operator < (const Node &b) const
	{
		return dis > b.dis;
	}
};

priority_queueq;
double f[N][N];
bool e[N][N];
bool DIR;
void inq(Point p, double dis)
{
	if (p.y < 1 || p.y > n || p.x < 1 || p.x > m)return;
	if (dis >= f[p.y][p.x])return;
	
	if (DIR)
	{
		if (p != p0 && p != p1 && cp(p0, p1, p) <= 0)return;
	}
	else
	{
		if (p != p0 && p != p1 && cp(p0, p1, p) >= 0)return;
	}

	f[p.y][p.x] = dis;
	if (!(p != p1))return;
	q.push({ p, dis });
}

const int dy[4] = { -1, 0, 0 ,1 };
const int dx[4] = { 0, -1, 1, 0 };
const int py[4] = { -1,-1,1,1 };
const int px[4] = { -1,1,-1,1 };
void bfs()
{
	while (!q.empty())q.pop();
	for (int i = 1; i <= n; ++i)
	{
		for (int j = 1; j <= m; ++j)
		{
			f[i][j] = inf;
			e[i][j] = 0;
		}
	}
	inq(p0, a[p0.y][p0.x]);
	while (!q.empty())
	{
		Point now = q.top().p; q.pop();
		if (e[now.y][now.x])continue; e[now.y][now.x] = 1;
		for (int k = 0; k < 4; ++k)
		{
			int y = now.y + dy[k];
			int x = now.x + dx[k];
			inq({ y, x }, f[now.y][now.x] + a[y][x]);
		}
		for (int k = 0; k < 4; ++k)
		{
			int y = now.y + py[k];
			int x = now.x + px[k];
			inq({ y, x }, f[now.y][now.x] + a[y][x] + (a[y][x] + a[now.y][now.x]) * (sqrt(2) - 1));
		}
	}
}
int main()
{
	while(~scanf("%d%d", &n, &m))
	{
		for (int i = 1; i <= n; ++i)
		{
			for (int j = 1; j <= m; ++j)
			{
				scanf("%d", &a[i][j]);
			}
		}
		scanf("%d%d%d%d", &p0.x, &p0.y, &p1.x, &p1.y);
		++p0.x; ++p0.y; ++p1.x; ++p1.y;

		double ans = 0;
		DIR = 0; bfs(); ans += f[p1.y][p1.x];
		DIR = 1; bfs(); ans += f[p1.y][p1.x];
		ans -= a[p0.y][p0.x];
		ans -= a[p1.y][p1.x];
		printf("%.2f\n", ans);
	}
	return 0;
}
/*
【题意】
其实就是轮廓线的点权和尽可能小,如果斜着走,从x走到y的话,会额外增加(v[x] + v[y]) * (sqrt(2) - 1)

【分析】
用叉积分路线,求最短路即可。

【数据】
9 0 1 9 9 9
9 9 1 2 2 9
9 9 2 0 2 9
9 9 1 1 2 9
9 9 3 3 1 1
9 9 9 9 9 9
(3 2) (6 5)
1 2 2 9
2 0 2 9
1 1 2 9
3 3 1 1

答案 = 27.04 = 3 + 17*(2^0.5)
4sqrt(2) 11sqrt(2) 2sqrt(2)
1 2 1 1 1 1
2 2 9
= 20 + 17sqrt(2) - 17

*/


你可能感兴趣的:(比赛总结)