“今日头条杯”首届湖北省大学程序设计竞赛(网络同步赛)

题目链接

A-Srdce and Triangle

(结论题)

题意:  已知一个正三角形ABC,在三角形内任意取一点D,连接AD,BD,CD,题目给出∠ADC,∠BDC和∠ADB,求以AD,BD,CD为边是否能建成一个三角形,可以就升序输出三个内角,否则输出-1 -1 -1.

题解:   结论是一定能建成三角形而且内角分别为题目给出的三个角每个减去60°(这里因为点D在三角形内,三个角都一定大于正三角形的每个角60°,因此不存在小于60°的角)

结论证明如下

见下图,高中常见的数学几何题要使图上三条变凑成一个三角形,那么有3种方法:1.对直线进行平移,旋转或对称,2.以一条直线为边建一个正多边形(该题的方法)

首先我们以AD边建一个正三角形,连接EC,对于这道题,如果我们能证明出BD=EC,那么三角形DCE就是答案所要的三角形了,这里易证三角形AEC全等于三角形ADB;接下来就是求角度了,第一个∠EDC直接通过∠ADC-60°即可,第二个∠CED=∠AEC-60°=∠ADB-60°,至于第三个角就不用求了,题目给出的三个角共360°,三角形内角和180°,因此∠ECD=∠CDB-60°.


代码如下

#include<iostream>
#include<cstring>
#include<string>
#include<cstdio>
#include<cmath>
#include<vector>
#include<queue>
#include<algorithm>
using namespace std;
#define inf 0x3f3f3f3f3f3f3f
#define ll long long
#define esp 1e-9
const int maxn = 1e5 + 500;
int main()
{
	int  a[5];
	while (~scanf("%d%d%d", &a[0], &a[1], &a[2])) {
		a[0] -= 60;
		a[1] -= 60;
		a[2] -= 60;
		sort(a, a + 3);
		printf("%.4lf %.4lf %.4lf\n", (double)a[0], (double)a[1], (double)a[2]);

	}
	return 0;
}

D-Who killed Cock Robin

(树)

题意:  给出一个有n个节点n-1条边的树,问你这颗数的所有子图的种类数目。例如下图:

一共有6种,分别是:(1)(2)(3)(1-2)(1-3)(1-2-3)

题解:     这里先定义每个节点的权值为以该节点为根的子图的种类的数目。那么对于所有叶子节点权值都为1(上图的2,3节点),而对于节点1,需要遍历他的每一个子树,并且子树间的权值需要相乘才得到节点1的权值。请看下图就可以发现它们之间的联系了。


代码如下

#include<iostream>
#include<cstring>
#include<string>
#include<cstdio>
#include<cmath>
#include<vector>
#include<set>
#include<algorithm>
using namespace std;
#define inf 0x3f3f3f3f
#define ll long long
const int maxn = 2e5 + 500;
const ll mod = 1e7 + 7;
vector<int>g[maxn];
int n, u, v;
ll vail[maxn];//每个节点的权值---这里定义为以该节点为根的子树(图)的种类数
void dfs(int u, int pre) {
	vail[u] = 1;
	for (int i = 0; i < g[u].size(); i++) {
		int v = g[u][i];
		if (v == pre)continue;
		dfs(v, u);
		vail[u] = vail[u] * (vail[v] + 1) % mod;
	}
}
int main() {
	scanf("%d", &n);
	for (int i = 1; i < n; i++) {
		scanf("%d%d", &u, &v);
		g[u].push_back(v);
		g[v].push_back(u);
	}
	dfs(1, -1);
	ll ans = 0;
	for (int i = 1; i <= n; i++)
		ans = (ans + vail[i]) % mod;
	printf("%lld\n", ans);
	return 0;
}

F-Flower Road

(水题)

题意:    给出一个n阶方正,和一个m表示旋转次数,随后给出n行n列的方正的值,然后m行(x  y  len)的修改(表示对方正中以(x,y)为左上角,边长为2*len的子方正进行顺时针旋转操作)eg:x=1 ,y=1,len=2


题解:   看到题目数据小直接暴力了,具体见代码。

代码如下

#include<iostream>
#include<cstring>
#include<string>
#include<cstdio>
#include<cmath>
#include<vector>
#include<queue>
#include<algorithm>
using namespace std;
#define inf 0x3f3f3f3f3f3f3f
#define ll long long
#define esp 1e-9
const int maxn = 2e3 + 500;
int dp[maxn][maxn];
int n, m, x, y, len, tmp;
int main() {
	scanf("%d%d", &n, &m);
	int t = 1;
	for (int i = 1; i <= n; i++)
		for (int j = 1; j <= n; j++)
			scanf("%d", &dp[i][j]);
	while (m--) {
		scanf("%d%d%d", &x, &y, &len);
		for(int i=x;i<x+len;i++)
			for (int j = y; j < y + len; j++) {
				tmp = dp[i][j];
				dp[i][j] = dp[i + len][j];
				dp[i + len][j] = dp[i + len][j + len];
				dp[i + len][j + len] = dp[i][j + len];
				dp[i][j + len] = tmp;
			}
	}
	for (int i = 1; i <= n; i++)
		for (int j = 1; j <= n; j++)
			dp[i][j] += max(dp[i - 1][j], dp[i][j - 1]);
	printf("%d\n", dp[n][n]);
	return 0;
}

G-Coins

(dfs+剪枝)

题意:有一场战斗,你每打一次可以获得N+K*Y的coins,K是卡片的数量(初始值为0),当你集齐X个coins时能够换一张卡片,现在给你t组数据,每组数据有N,X,Y,Z,问你最少多少次战斗可以拥有Z个coins.

解法:这里可以用2种方法写,一开始为了思路清晰采用了dfs+剪枝,交上去ac了,不过自己写了一组数据本地爆栈了,运行不了,eg:1 1 100000 1 1000000000 ,原来是因为windows系统编译栈预设不给开太大,所有需要加一句:

#pragma comment(linker, "/STACK:102400000,102400000")

不过提交过去的评测系统是linux不担心爆栈才ac的。(还以为因为那么数据太水就改成while+剪枝的写法本地就可以运行了,也是ac代码)

代码如下

dfs+剪枝:

#include<cstdio>
#include<algorithm>
using namespace std;
#define inf 0x3f3f3f3f3f3f3f
#define ll long long
ll n, x, y, z, ans;
void dfs(ll sum, ll n, ll t) {//n值当前每交易一次能获得的coins
    if (t >= ans) return;//剪枝1
    ll cnt = (z - sum) / n;
    if ((z - sum) % n)cnt++;
    ans = min(ans, t + cnt);
    if (sum >= x) dfs(sum - x*(sum / x), n + y*(sum / x), t);
    else {
        cnt = (x - sum) / n;//剪枝2,直接跳跃式dfs
        if ((x - sum) % n)cnt++;
        dfs(sum + cnt*n, n, t + cnt);
    }
}
int main() {
    int t;
    scanf("%d", &t);
    while (t--) {
        scanf("%lld%lld%lld%lld", &n, &x, &y, &z);
        ans = inf;
        dfs(0, n, 0);
        printf("%lld\n", ans);
    }
    return 0;
}

(代码内容同上,只是当时本地爆栈的改写为while的形式)

#include<cstdio>
#include<algorithm>
using namespace std;
#define inf 0x3f3f3f3f3f3f3f
#define ll long long
ll n, x, y, z,t, ans, sum, cnt;
int main() {
	int q;
	scanf("%d", &q);
	while (q--) {
		scanf("%lld%lld%lld%lld", &n, &x, &y, &z);
		ans = inf, sum = 0, t = 0;
		while (1) {
			if (t >= ans)break;
			cnt = (z - sum) / n;
			if ((z - sum) % n)cnt++;
			ans = min(ans, t + cnt);
			if (sum >= x) n += y*(sum / x),sum -= x*(sum / x) ;
			else {
				cnt = (x - sum) / n;
				if ((x - sum) % n)cnt++;
				sum += cnt*n, t += cnt;
			}
		}
		printf("%lld\n", ans);
	}
	return 0;
}

H-GSS and Simple Math Problem

(高精度乘法)

题意:给出n个数,要求输出n个数相乘的结果

题解:这里直接上一波py了,FFT代码量太大

代码如下

n=int(input())
ans=int(1);
while n>0:
    a=int(input())
    ans=ans*a
    n=n-1
print(ans)

I-Five Day Couple

(可持久化01字典树)

题意:给出n个数,再给出q次询问,每次询问将 l 到 r 区间中与x异或得到的最大值输出出来。

题解:比赛的时候我是使用加速的输入输出流卡时间ac的(这个可持久化01字典树我也不咋会,直接copy一手板子了,找时间学习一波整理模板)

代码如下

暴力:

#include<iostream>
#include<cstring>
#include<string>
#include<cstdio>
#include<cmath>
#include<vector>
#include<queue>
#include<algorithm>
using namespace std;
#define inf 0x3f3f3f3f3f3f3f
#define ll long long
#define esp 1e-9
const int maxn = 1e5 + 500;
inline int readint() {
    char c = getchar();
    while (!isdigit(c))c = getchar();
    int x = 0;
    while (isdigit(c)) {
        x = x * 10 + c - '0';
        c = getchar();
    }
    return x;
}
int buf[10];
inline void writeint(int i) {
    int p = 0;
    if (i == 0) {
        buf[0] = 0;
        p++;
    }
    else {
        while (i) {
            buf[p++] = i % 10;
            i /= 10;
        }
    }
    for (int j = p - 1; j >= 0; j--)
        putchar('0' + buf[j]);
    putchar('\n');
}
int a[maxn], n, m, x, ans, l, r;
int main() {
    n = readint();
    for (int i = 1; i <= n; i++) a[i] = readint();
    m = readint();
    while (m--) {
        x = readint();
        l= readint();
        r= readint();
        ans = 0;
        for (int i = l; i <= r; i++) ans = max(ans, a[i] ^ x);
        writeint(ans);
    }
    return 0;
}

可持久化01字典树:

#include<iostream>
#include<cstring>
#include<string>
#include<cstdio>
#include<cmath>
#include<vector>
#include<queue>
#include<algorithm>
using namespace std;
#define inf 0x3f3f3f3f3f3f3f
#define ll long long
const int maxn = 1e5 + 500;
//可持久化01字典树模板
int a[maxn], rt[maxn],n;
struct Trie
{
	int top;
	int child[maxn * 33][2], sum[maxn * 33];
	int insert(int x, int val)
	{
		int tmp, y; tmp = y = ++top;
		for (int i = 30; i >= 0; --i)
		{
			child[y][0] = child[x][0]; 
			child[y][1] = child[x][1];
			sum[y] = sum[x] + 1;
			int t = val >> i & 1;
			x = child[x][t];
			child[y][t] = ++top;
			y = child[y][t];
		}
		sum[y] = sum[x] + 1;
		return tmp;
	}
	int query(int l, int r, int val)
	{
		int tmp = 0;
		for (int i = 30; i >= 0; --i)
		{
			int t = val >> i & 1;
			if (sum[child[r][t ^ 1]] - sum[child[l][t ^ 1]])
				tmp += (1 << i), r = child[r][t ^ 1], l = child[l][t ^ 1];
			else r = child[r][t], l = child[l][t];
		}
		return tmp;
	}
}trie;
int main()
{
	scanf("%d", &n);
	for (int i = 1; i <= n; ++i) scanf("%d", &a[i]);
	for (int i = 1; i <= n; ++i) rt[i] = trie.insert(rt[i - 1], a[i]);
	int q;
	scanf("%d", &q);
	while (q--)
	{
		int l, r, x;
		scanf("%d%d%d", &x, &l, &r);
		int ans = trie.query(rt[l - 1], rt[r], x);
		printf("%d\n", ans);
	}
	return 0;
}


  • 5
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值