儒略日
思路
出题人(1582/10/4 ~ 1582/10/15)
就把他拆成两部分,一个是删去之前的,一种是删去之后的。
删去之前的,闰年 4 年一次,就对他进行日期的拆分。
删去之后,闰年 400 一循环,按照 400 搞一搞,就做完了。
code
#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define int long long
#define N 100010
#define M 1010
using namespace std;
const int mod = 1e9+7;
const int inf = 0x3f3f3f3f;
int q, n;
int yu[13] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
int read() {
int s = 0, f = 0; char ch = getchar();
while (!isdigit(ch)) f |= (ch == '-'), ch = getchar();
while (isdigit(ch)) s = s * 10 + (ch ^ 48), ch = getchar();
return f ? -s : s;
}
void work1() {
int year = -4712, mon = 1, day = 1, t = n / (365 * 3 + 366);
year += t * 4, n -= t * (365 * 3 + 366);
for (int i = 1; i <= 3; i++) {
int res = 365 + (year % 4 == 0);
if (n >= res) year++, n -= res;
else break;
}
for (int i = 1; i <= 12; i++) {
int res = yu[i] + (i == 2 && (year % 4 == 0));
if (res <= n) mon++, n -= res;
else break;
}
if (year <= 0) cout << day + n<< " " << mon << " " << 1 - year << " BC
";
else cout << day + n << " " << mon << " " << year << "
";
}
void work2() {
int year = 1582, mon = 10, day = 15;
if (n <= 16) {
cout << day + n << " " << mon << " " << year << "
";
return ;
}
mon++, day = 1, n -= 17;
if (n < 30) {
cout << day + n << " " << mon << " " << year << "
";;
return;
}
mon++, n -= 30;
if (n < 31) {
cout << day + n << " " << mon << " " << year << "
";;
return;
}
mon = 1, n -= 31, year++;
int per = (97 * 366 + 303 * 365);
int t = n / per;
n -= per * t, year += t * 400;
for (int i = 1; i <= 400; i++) {
int res = 365 + (year % 4 == 0 && (year % 400 == 0 || year % 100 != 0));
if (n >= res) year++, n -= res;
else break;
}
for (int i = 1; i <= 12; i++) {
int res = yu[i] + (i == 2 && (year % 4 == 0 && (year % 400 == 0 || year % 100 != 0)));
if (n >= res) mon++, n -= res;
else break;
}
cout << day + n << " " << mon << " " << year << "
";
}
signed main() {
freopen("julian3.in", "r", stdin);
freopen("julian.out", "w", stdout);
q = read();
for (int i = 1; i <= q; i++) {
n = read();
if (n <= 2299160) work1();
else n -= 2299161, work2();
}
}
动物园
思路
简化题意
我们可以把题目看成,给你 n 个数,和 m 个条件,这 m 个条件中的 p,q 代表,前边那 n 个数中如果有二进制的第 p 位是 1, 那么必须有第 q 个饲料。
可以发现判断 n 个数中有没有第 p 位是 1,与判断这 n 个数的或的第 p 位是 1 没有什么不同。所以可以直接判断这 n 个数的按位或的第 p 位是否是 1,我们把这 n 个数的按位或看做 (s)。
- 显然当 (m = 0) 时,答案就是 (2 ^ k)。
因为没有约束条件,所有的动物都可以养。
- 当 (m ot= 0) 时,我们可以把 m 种条件看做有没有确定一个二进制位。
就是如果 s 的第 p 位为 1,那么就会买 q 种饲料。也就是说如果我们买了第 q 种饲料,那么我们的第 p 位就可以是 0 也可以是 1。如果没买那就一定是 0。
因为 q 种饲料都是不相同的,所以买当前这种饲料不会对其他饲养的动物产生影响。
也就是说一组 ((p, q)) 只能确定一个二进制位 p。
可以 (operatorname{O} (n)) 的判断一下 s 的二进制的第 p 位是否为 1。如果是 1 ,那就说明当前这一位可以随便取,否则就只能是取 0。
对于那些 m 个约束条件中没有出现的二进制位,也是可以随便取的。
最后问的是可以饲养的动物总数,简单乘一下就好。
注意判断 (k = 64 & n = 0 & m = 0) 的情况(会爆掉 unsigned long long
)。
code
#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define ll long long
#define N 100010
#define M 1010
using namespace std;
const int mod = 1e9+7;
const int inf = 0x3f3f3f3f;
int n, m, c, k, p, q;
unsigned long long a, x;
int wei[N];
int read() {
int s = 0, f = 0; char ch = getchar();
while (!isdigit(ch)) f |= (ch == '-'), ch = getchar();
while (isdigit(ch)) s = s * 10 + (ch ^ 48), ch = getchar();
return f ? -s : s;
}
int main() {
n = read(), m = read(), c = read(), k = read();
for (int i = 1; i <= n; i++) {
cin >> a;
x |= a;
}
for (int i = 0; i < k; i++) wei[i] = 1;
for (int i = 1; i <= m; i++) {
p = read(), q = read();
if ((1ull << p) & x) wei[p] = 1;
else wei[p] = 0;
}
if (!n) {
if (!m && k == 64) {
puts("18446744073709551616");
} else {
unsigned long long ans = 1;
for (int i = 0; i < k; i++)
if (wei[i] == 1) ans *= 2;
cout << ans - n;
}
return 0;
}
unsigned long long ans = 1;
for (int i = 0; i < k; i++)
if (wei[i] == 1) ans *= 2;
cout << ans - n;
}
T3
思路
可以发现每个元素的答案最后可以拆分为 (x imes a + b) 这种形式(其中 a 为原来的元素,x 为一共乘上的数,b是加的数的乘积的和)
可以用一个 mul 来表示当前这次操作之后会使各个元素变为原来的多少倍,可以用记忆化搜索得到。
再考虑加法操作,再在拓扑序上 DP,求得每种操作被调用多少次,注意倒序进行,通过调用者更新被调用者。
某加法操作的贡献为调用次数 + 影响到它乘法操作的次数。
两者贡献量相同,在代码中用 cnt 记录了两者的和。
code
#include <queue>
#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define ll long long
#define N 100010
#define M 1010000
using namespace std;
const int mod = 998244353;
const int inf = 0x3f3f3f3f;
int n, m, q; vector<int> ed[N];
ll mul[N], cnt[N], a[N], val[N];
int siz[N], qu[N], opt[N], pos[N], du[N];
ll read() {
int s = 0, f = 0; char ch = getchar();
while (!isdigit(ch)) f |= (ch == '-'), ch = getchar();
while (isdigit(ch)) s = s * 10 + (ch ^ 48), ch = getchar();
return f ? -s : s;
}
ll dfs(int x) {
if (mul[x] != -1) return mul[x];
if (opt[x] != 3) {
mul[x] = (opt[x] == 1) ? 1 : val[x];
return mul[x];
}
mul[x] = 1;
for (int i = siz[x] - 1; i >= 0; i--) {
int to = ed[x][i];
mul[x] = (mul[x] * dfs(to)) % mod;
}
return mul[x];
}
void topsort() {
queue<int> q;
for (int i = 1; i <= m; i++)
if (!du[i]) q.push(i);
while (!q.empty()) {
int x = q.front(); q.pop();
ll prod = 1;
for (int i = siz[x] - 1; i >= 0; i--) {
int to = ed[x][i];
cnt[to] = (cnt[to] + cnt[x] * prod % mod) % mod;
du[to]--;
if (!du[to]) q.push(to);
prod = (prod * mul[to]) % mod;
}
}
for (int i = 1; i <= m; ++ i)
if (opt[i] == 1)
a[pos[i]] = (a[pos[i]] + val[i] * cnt[i] % mod) % mod;
}
int main() {
n = read();
for (int i = 1; i <= n; i++) a[i] = read();
m = read();
for (int i = 1; i <= m; i++) {
opt[i] = read();
if (opt[i] == 1) pos[i] = read(), val[i] = read();
if (opt[i] == 2) val[i] = read();
if (opt[i] == 3) {
siz[i] = read();
for (int j = 1, x; j <= siz[i]; j++) {
x = read(), ed[i].push_back(x);
du[x]++;
}
}
}
memset(mul, -1, sizeof mul);
for (int i = 1; i <= m; i++)
if (!du[i]) mul[i] = dfs(i);
q = read();
for (int i = 1; i <= q; i++) qu[i] = read();
ll prod = 1;
for (int i = q; i; i--) {
cnt[qu[i]] = (cnt[qu[i]] + prod) % mod;
prod = (prod * mul[qu[i]]) % mod;
}
for (int i = 1; i <= n; ++ i) a[i] = a[i] * prod % mod;
topsort();
for (int i = 1; i <= n; i++) cout << a[i] << " ";
}
T4
20 pts
三只蛇的时候最好判断,只需要判断一下最大的那只蛇减去最小的是不是大于等于中间的那只蛇就行,如果是那么还剩 1 只,不是就剩下 3 只。
#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define ll long long
#define N 100010
#define M 1010
using namespace std;
int T, n;
int read() {
int s = 0, f = 0; char ch = getchar();
while (!isdigit(ch)) f |= (ch == '-'), ch = getchar();
while (isdigit(ch)) s = s * 10 + (ch ^ 48), ch = getchar();
return f ? -s : s;
}
namespace SUB1 {
struct node {
int a, id;
}a[4];
bool cmp(node a, node b) {
if (a.a != b.a) return a.a < b.a;
else return a.id < b.id;
}
int check(int x, int y) {
if (a[x].a > a[y].a) return x;
else if (a[x].a == a[y].a) {
if (a[x].id > a[y].id) return x;
else return y;
}
else return y;
}
bool cmp1(node a, node b) {
return a.id < b.id;
}
void work() {
// for (int i = 1; i <= n; i++) a[i].a = read(), a[i].id = i;
sort(a + 1, a + n + 1, cmp);
a[3].a -= a[1].a;
if (check(3, 2) == 3) puts("1");
else puts("3");
a[3].a += a[1].a;
sort(a + 1, a + n + 1, cmp1);
}
}
int main() {
T = read();
int i = 1;
while (T--) {
n = read();
if (i >= 2) {
for (int i = 1, x, y; i <= n; i++) {
x = read(), y = read();
SUB1::a[x].a = y;
}
} else {
for (int i = 1; i <= n; i++)
SUB1::a[i].a = read(), SUB1::a[i].id = i;
}
if (n <= 3) SUB1::work();
i++;
}
return 0;
}