2019.7.31 金华正睿集训总结Day4(ACM)

今天是ACM赛!

我真是太菜了!

A - 10^N+7

来源

You are given three non-negative integers, x, y, z. Your task is to find the smallest non-negative integer n with all of the following conditions:
· n mod 17=x
· n mod 107=y
· n mod 1000000007(=109+7)=z

这是一道签到题

用条件三枚举 n 的取值,判断是否符合前两个条件就行了

#include <bits/stdc++.h>
using namespace std;
const long long a = 17, b = 107, c = 1e9 + 7;
int main()
{
	long long n, i = 0;
	long long x, y, z;
	cin >> x >> y >> z;
	while (1)
	{
		n = i * c + z;
		if (n % a == x && n % b == y) 
		{
			cout << n << endl;
			return 0;
		}
		i++; 
	}
	return 0;
}

B - Coins

来源

There are 1-, 5-, 10-, 50-, 100-, 500- yen coins, and you have an infinite number of coins of each type.
For a given positive integer x, let f(x) be the smallest number of coins you have to use to pay exactly x yen. For example, f(2018)=9 because 2018=1+1+1+5+10+500+500+500+500.
You are given a positive integer N. Count the number of positive integers x such that f(x)=N.
1≤N≤1018

这也是道签到题

我们可以想到 5 个 1 元可以用 1 个 5 元代替,2 个 5 元可以用 1 个 10 元代替

同理,50, 100 也可以想到

因为最终求的总价值种数是不能重复的,所以必然不存在可以替换的情况

所以每种硬币的最大个数都可以知道,而 500 不能被替换,所以不用考虑 500 的个数

就这样枚举每种硬币个数,判断总个数是否<=n就可以了

#include <bits/stdc++.h>
using namespace std;
int main()
{
	long long n;
	int ans = 0;
	cin >> n;
	for (int a = 0; a < 5; a++)
	for (int b = 0; b < 2; b++)
	for (int c = 0; c < 5; c++)
	for (int d = 0; d < 2; d++) 
	for (int e = 0; e < 5; e++)
	if (a + b + c + d + e <= n) ans++;
	cout << ans << endl;
	return 0;
}

C - Equiangular

来源

You have a regular N-sided convex polygon. You are going to choose 3 or more vertices from the polygon, and make a new convex polygon P formed by chosen vertices. You very much like equiangular polygons (polygons whose vertex angles are all equal), so the polygon P must be equiangular.
Count the number of equiangular polygons that you can get in the above-mentioned way. Here, two polygons are considered to be the same if they are congruent, that is, one has the same shape and size as the other or as the mirror image of the other.
3≤N≤1012

根据我们初中学的知识,我们知道在圆中,等角所对的弦相等

所以我们可以想到在正多边形中,构造出来的等角多边形的等角对应的边数是相等的

所以可以求约数(雾Σ(☉▽☉"a,还是不怎么理解)

#include <bits/stdc++.h>
using namespace std;
long long n, ans = 0;
int main()
{
	cin >> n;
    for (long long i = 2; i * i <= n; i++) 
	if (n % i == 0) 
	{
        ans += i + 1 >> 1;
        if (i * i != n) ans += n / i + 1 >> 1;
    }
    ans++;
    ans -= !(n & 1);
    cout << ans;
	return 0;
}

D

E

F - Yet another vector problem

来源

You’re given a 0-based array a of length n. Answer Q queries of form: what is sum of elements a[i], such as i modulo p = q, for given p and q.

根据数据范围,如果询问一次搜索一次必然是会超时的

所以我们可以分成两个部分

先预处理 p <= sqrt(n)范围内的答案

在询问时,若 p <= sqrt(n) 就直接输出已有的答案

否则再累计符合询问的答案

#include <bits/stdc++.h>
#define N 1100000
using namespace std;
int n, m, a[N], f[1100][1100], t;
int main()
{
	cin >> n >> m;
	t = sqrt(n) + 1;
	for (int i = 0; i < n; i++) 
	scanf("%d", &a[i]);
	for (int i = 1; i <= t; i++)
	for (int j = 0; j < n; j++)
	f[i][j % i] += a[j];
	while (m--)
	{
		int p, q;
		scanf("%d%d", &q, &p);
		if (p > t)
		{
			int ans = 0;
			for (int i = q; i < n; i += p) ans += a[i];
			printf("%d\n", ans);
		}
		else printf("%d\n", f[p][q]);
	}
	return 0;
}

G - Prefix Suffix Free

来源

You are given a string S consisting of lowercase English letters. Count the number of strings T that satisfies all of the following conditions:
T is a string of the same length as S, consisting of lowercase English letters.
For all K ( 1≤K≤|S| ), the string formed by the first K letters of S does not coincide with the string formed by the last K letters of T.
Since the answer can be very large, find the number modulo 109+7.

考虑用总方案数减去不可行的方案数

先做一遍KMP

再快速幂得到总方案数

若最长的相同前缀后缀的长度,即 next[i] 为 0, 就把这部分减掉

#include <bits/stdc++.h>
#define N 1100000
using namespace std;
long long ans, p = 1000000007, k, sum, n, next[N];
char s[N];
long long Pow(long long a, long long b)
{
    long long tmp = 1;
    while (b != 0)
    {
        if (b % 2 == 1) tmp = tmp * a % p;
        b /= 2;
        a = a * a % p;
    }
    return tmp;
}
int main()
{
	cin >> s + 1;
	n = strlen(s + 1);
	next[1] = 0;
	for (int i = 2, j = 0; i <= n; i++) 
	{
		while (j > 0 && s[i] != s[j + 1]) j = next[j];
		if (s[i] == s[j + 1]) j++;
		next[i] = j;
	}
	ans = Pow(26, n) % p;
	for (int i = 1; i <= n; i++)
	{
		if (!next[i]) ans = (ans - Pow(26, n - i) + p) % p;
	}
	cout << ans << endl;
	return 0;
}

I - Grouping

来源

Suppose there are N people in ZJU, whose ages are unknown. We have some messages about them. The i-th message shows that the age of person si is not smaller than the age of person ti. Now we need to divide all these N people into several groups. One’s age shouldn’t be compared with each other in the same group, directly or indirectly. And everyone should be assigned to one and only one group. The task is to calculate the minimum number of groups that meet the requirement.

根据题意,可以想到最小组数应该为最长链长度

因为可能存在环,所以tarjan缩点

然后求最长路就可以了

要注意,这是多组数据啊!!!

#include <bits/stdc++.h>
#define N 110000
using namespace std;
int dfn[N], low[N], v[N], vis[N], d[N], c[N], head[N], dp[N];
int n, m, st[N], ans, first[N], tot, top, num, toto, cnt, scc[N];
queue <int> q;
struct Xiaozhan
{
	int next, to;
}f[N];
struct Wangyibo
{
	int next, to;
}g[N];
void add(int x, int y)
{
	f[++tot].to = y;
	f[tot].next = first[x];
	first[x] = tot;
}
void addd(int x, int y)
{
	g[++toto].to = y;
	g[toto].next = head[x];
	head[x] = toto;
}
void tarjan(int x)
{
	dfn[x] = low[x] = ++num;
	v[x] = 1;
	st[++top] = x;
	for (int i = first[x]; i; i = f[i].next)
	{
		int y = f[i].to;
		if (!dfn[y])
		{
			tarjan(y);
			low[x] = min(low[x], low[y]);
		}
		else if (v[y]) low[x] = min(low[x], dfn[y]);
	}
	if (low[x] == dfn[x])
	{
		cnt++;
		int y;
		do
		{
			y = st[top--];
			v[y] = 0;
			c[y] = cnt;	
			scc[cnt]++;
		}while (x != y);
	}
}
int dfs(int x)
{
	if (dp[x]) return dp[x];
	int sum = scc[x];
	for (int i = head[x]; i; i = g[i].next)
	{
		int y = g[i].to;
		int k = scc[x];
		sum = max(sum, dfs(y) + k);
	}
	return dp[x] = sum;
}
int main()
{
	while (scanf("%d%d", &n, &m) != EOF)
	{
		memset(dfn, 0, sizeof(dfn));
		memset(low, 0, sizeof(low));
		memset(f, 0, sizeof(f));
		memset(g, 0, sizeof(g));
		memset(head, 0, sizeof(head));
		memset(first, 0, sizeof(first));
		memset(c, 0, sizeof(c));
		memset(d, 0, sizeof(d));
		memset(vis, 0, sizeof(vis));
		memset(v, 0, sizeof(v));
		memset(st, 0, sizeof(st));
		memset(scc, 0, sizeof(scc));
		memset(dp, 0, sizeof(dp));
		ans = 0;
		tot = 0;
		top = 0;
		num = 0;
		toto = 0;
		cnt = 0;
		for (int i = 1; i <= m; i++)
		{
			int x, y;
			scanf("%d%d", &x, &y);
			if (x != y) add(x, y);
		} 
		for (int i = 1; i <= n; i++)
		{
			if (!dfn[i]) tarjan(i);
		}
		for (int x = 1; x <= n; x++)
		for (int i = first[x]; i; i = f[i].next)
		{
			int y = f[i].to;
			if (c[x] == c[y]) continue;
			addd(c[x], c[y]); 
		}
		for (int i = 1; i <= cnt; i++)
		ans = max(ans, dfs(i));
		printf("%d\n", ans);
	}
	return 0;
}

J

K

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值