2022 ICPC 杭州

https://codeforces.com/gym/104090

唉我还是太菜了

A.Modulo Ruins the Legend

纠正一下:第一种情况最小是sum2 第二种情况最坏是sum2 可以比sum2更小

为什么? 因为g是m的因数 所以后面就会循环了

题解中说明:其实d只用取0或者1 因为相当于对每个位置加上一个平均数 也就只加了ns 但是可能这个平均数可能为分数 所以d取1和0即可代表所有情况

#include <bits/stdc++.h>
#define endl "\n"
#define INF 0x3f3f3f3f
#define LLINF 0x3f3f3f3f3f3f3f3f
#define IOS ios::sync_with_stdio(false);cin.tie(0);cout.tie(0)
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
typedef pair<ll, ll> pll;

ll exgcd(ll a, ll b, ll& x, ll& y) {
    if (!b) {
        x = 1, y = 0;
        return a;
    }
    ll d = exgcd(b, a % b, x, y);
    ll tx = x;
    x = y, y = tx - y * (a / b);
    return d;
}

signed main() {
    IOS;
    ll n, mod; cin >> n >> mod;
    ll sum = 0;
    for (int i = 1; i <= n; i++) {
        ll t; cin >> t;
        sum += t;
    }

    ll a = n, b = n * (n + 1) / 2;
    ll s, dt;
    ll d = exgcd(a, b, s, dt);
    sum %= mod;

    ll k, t;
    ll g = exgcd(d, mod, k, t);

    ll z = (mod - sum + g - 1) / g;
    (k *= z) %= mod;
    
    s = ((s % mod * k) % mod + mod) % mod, dt = ((dt % mod * k) % mod + mod) % mod;

    cout << (z * g + sum - mod) << endl;
    cout << s << " " << dt << endl;
}

C. No Bug No Game

分析:

选物品的顺序很重要 但是题目并没有要求顺序

有一个关键的性质 最多只有一个物品是取不完的

此时会有疑问 当前转移到i 后面的不是还没转移嘛

其实并不是 因为最多只有一个物品取不完 后面的还是按照都选的转移即可

const int N = 3010;
long long dp[N][N][5];
void Immortality()
{
	int n, k;
	cin >> n >> k;
	long long sum = 0;
	vector<vector<int>> p(n + 1);
	for (int i = 1; i <= n; i++)
	{
		int t;
		cin >> t;
		sum += t;
		p[i].resize(t + 1);
		for (int j = 1; j <= t; j++)
			cin >> p[i][j];
	}
	if (sum <= k)
	{
		long long ans = 0;
		for (int i = 1; i <= n; i++)
		{
			int t = (p[i].size() - 1);
			ans += p[i][t];
		}
		cout << ans << endl;
		return;
	}
	memset(dp, -0x3f, sizeof dp);
	dp[0][0][1] = 0;
	dp[0][0][0] = 0;
	for (int i = 1; i <= n; i++)
	{
		int t = (p[i].size() - 1);
		for (int j = 0; j <= k; j++)
		{
			dp[i][j][0] = dp[i - 1][j][0];
			dp[i][j][1] = dp[i - 1][j][1];
			if (j >= t)
			{
				dp[i][j][0] = max(dp[i - 1][j][0], dp[i - 1][j - t][0] + p[i][t]);
				dp[i][j][1] = max(dp[i - 1][j][1], dp[i - 1][j - t][1] + p[i][t]);
			}
			for (int z = 1; z < t; z++)
				if (j >= z)
					dp[i][j][0] = max(dp[i][j][0], dp[i - 1][j - z][1] + p[i][z]);
		}
	}
	cout << max(dp[n][k][1], dp[n][k][0]) << endl;
}

K. Master of Both

题意:根据设置的字符大小顺序

求字符串逆序对的个数

分析:

很明显 我们不能对每一种字符顺序求一次逆序对

#include "bits/stdc++.h"

using namespace std;
using i64 = long long;

constexpr int N = 26;

constexpr int M = 2E6;

i64 cnt[M + 10];
i64 add;
i64 num[N][N];
i64 ed[M + 10];

class Trie {
 public:
  int tot;
  vector<vector<int>> t;
  Trie(const int &n = 2E6) : t(n, vector<int>(N)), tot(0) {}
  inline void insert(const string &s) {
    int SIZE = s.size();
    int u = 0;
    for (int i = 0; i < SIZE; i++) {
      int c = s[i] - 'a';
      for (int j = 0; j < N; j++) {
        if (c != j && t[u][j]) {
          num[c][j] += cnt[t[u][j]];
        }
      }
      if (t[u][c] == 0) {
        t[u][c] = ++tot;
      }
      u = t[u][c];
      cnt[u]++;
    }
    ed[u]++;
    add += cnt[u] - ed[u];
  }
};

void solve() {
  int n, q;
  cin >> n >> q;
  Trie tree;
  for (int i = 0; i < n; i++) {
    string s;
    cin >> s;
    tree.insert(s);
  }
  for (int i = 0; i < q; i++) {
    string s;
    cin >> s;
    i64 ans = 0;
    for (int j = 0; j < N; j++) {
      for (int k = j + 1; k < N; k++) {
        ans += num[s[j] - 'a'][s[k] - 'a'];
      }
    }
    cout << ans + add << '\n';
  }
}

int main() {
  int tt = 1;
  while (tt--) {
    solve();
  }
  return 0;
}
posted @ 2022-12-14 21:23  wzx_believer  阅读(358)  评论(1编辑  收藏  举报