CSP-S 2020 題解

儒略日

思路

出題人(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\n";
  else cout << day + n << " " << mon << " " << year << "\n";
}

void work2() {
  int year = 1582, mon = 10, day = 15;
  if (n <= 16) {
    cout << day + n << " " << mon << " " << year << "\n";
    return ;
  }
  mon++, day = 1, n -= 17;
  if (n < 30) {
    cout << day + n << " " << mon << " " << year << "\n";;
    return;
  }
  mon++, n -= 30;
  if (n < 31) {
    cout << day + n << " " << mon << " " << year << "\n";;
    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 << "\n";
}

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();
  }
}

T2

思路

用一個東西或一下 a 可以得到當前的每隻動物能有那幾位是 1。
根據給出的 p,q 看看哪一位固定了,最後的時候如果這一位固定了,那就乘 1,沒固定就乘 2,注意特盼 n=0,m=0,k=64 的情況。

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) {
      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 \times 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;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章