2020 CCPC Wannafly Winter Camp Day5

PTA
牛客

A. Alternative Accounts

题意:
现在有\(n\)个账号,举办\(k,k\leq 3\)场比赛。
现在每个人可能有多个账号,但每次只能用一个账号参加一场比赛。
现在给出\(k\)场比赛的参赛账号。
现在询问最少有多少人参加比赛。

思路:
分情况讨论即可。
我们可以直接认为\(k=3\)来分析:

  • 若某个账号都出现在三场比赛中,那么直接让这个账号归属于某一人;
  • 若某个账号出现在两场比赛中,那么这个账号可以和仅出现在另外一场比赛一次的账号进行匹配;不能匹配则不匹配;
  • 若某个账号出现一次,现在剩下这些出现一次的账号可以互相匹配。

细节见代码,可能写得有点乱:


Code

#include<bits/stdc++.h>
typedef long long ll;
typedef unsigned long long ull;
typedef double db;
const int MAXN = 1e5+5,MAXM = 1e6+5,MOD = 998244353,INF = 0x3f3f3f3f,N=2e5;
const ll INFL = 0x3f3f3f3f3f3f3f3f;
const db eps = 1e-7;
#define lson o<<1,l,m
#define rson o<<1|1,m+1,r
#define mid l + ((r-l)>>1)
#define pii pair<int,int>
#define vii vector<pii>
#define vi vector<int>
#define x first
#define y second
using namespace std;

int n,k,sta[MAXN],cnt[10];
int main(){
    ios::sync_with_stdio(false);cin.tie(0);
    cin>>n>>k;
    for(int i=1;i<=k;i++){
        int m,x;
        cin>>m;
        while(m--){
            cin>>x;
            sta[x] |= 1<<(i-1);
        }
    }
    for(int i=1;i<=n;i++){
        if(sta[i])cnt[sta[i]]++;
    }
    if(k==1){
        cout<<cnt[1]<<'\n';
    }else if(k==2){
        cout << cnt[1] + cnt[2] + cnt[3] - min(cnt[1],cnt[2])<<'\n';
    }else{
        int ans=0;
        for(int i=1;i<8;i++)ans+=cnt[i];
        int tmp;
        tmp = min(cnt[3], cnt[4]);
        cnt[3] -= tmp;
        cnt[4] -= tmp;
        ans -= tmp;
        tmp = min(cnt[5],cnt[2]);
        cnt[5] -= tmp;
        cnt[2] -= tmp;
        ans -= tmp;
        tmp = min(cnt[6],cnt[1]);
        cnt[6] -= tmp;
        cnt[1] -= tmp;
        ans -= tmp;
        tmp = min(min(cnt[1],cnt[2]),cnt[4]);
        cnt[1] -= tmp;
        cnt[2] -= tmp;
        cnt[4] -= tmp;
        ans -= 2*tmp;
        tmp = min(cnt[1], cnt[2]);
        cnt[1] -= tmp;
        cnt[2] -= tmp;
        ans -= tmp;
        tmp = min(cnt[1],cnt[4]);
        cnt[1] -= tmp;
        cnt[4] -= tmp;
        ans -= tmp;
        tmp = min(cnt[2],cnt[4]);
        cnt[2] -= tmp;
        cnt[4] -= tmp;
        ans -= tmp;
        cout<<ans<<'\n';
    }
    return 0;
}

E. Matching Problem

题意:
给出两个序列\(a,b\),定义两个序列匹配当且仅当:

  • 长度相等,且若\(a_i=a_j\),有\(b_i=b_j\)

现在\(a\)的长度不超过\(300\)\(b\)的长度为\(4\)。问\(a\)有多少个子序列与\(b\)匹配。

思路:
直接暴力枚举子序列的前三个数,最后一个数直接预处理后缀即可。


Code

/*
 * Author:  heyuhhh
 * Created Time:  2020/1/16 14:58:26
 */
#include <iostream>
#include <algorithm>
#include <cstring>
#include <vector>
#include <cmath>
#include <set>
#include <map>
#include <queue>
#include <iomanip>
#define MP make_pair
#define fi first
#define se second
#define sz(x) (int)(x).size()
#define all(x) (x).begin(), (x).end()
#define INF 0x3f3f3f3f
#define Local
#ifdef Local
  #define dbg(args...) do { cout << #args << " -> "; err(args); } while (0)
  void err() { std::cout << '\n'; }
  template<typename T, typename...Args>
  void err(T a, Args...args) { std::cout << a << ' '; err(args...); }
#else
  #define dbg(...)
#endif
void pt() {std::cout << '\n'; }
template<typename T, typename...Args>
void pt(T a, Args...args) {std::cout << a << ' '; pt(args...); }
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
//head
const int N = 300 + 5;

int n;
int a[N];
int b[5], c[5];

int suf[N][N];
ll ans;

void gao(int pos, int cnt) {
    if(pos >= n) return;
    if(cnt == 3) {
        int op = 0;
        for(int i = 1; i <= 3; i++) {
            if(b[4] == b[i]) op = i;
        }   
        if(op == 0) {
            ans += n - pos - suf[pos + 1][c[1]] - suf[pos + 1][c[2]] - suf[pos + 1][c[3]];
            if(c[1] == c[2]) ans += suf[pos + 1][c[1]];
            if(c[2] == c[3]) ans += suf[pos + 1][c[2]];
            if(c[1] == c[3]) ans += suf[pos + 1][c[3]];
            if(c[1] == c[2] && c[2] == c[3]) ans -= suf[pos + 1][c[1]];
        } else {
            ans += suf[pos + 1][c[op]];   
        }
        return;
    }
    gao(pos + 1, cnt);
    int x = a[pos + 1];
    int ok = 1;
    for(int i = 1; i <= cnt; i++) {
        if((b[cnt + 1] == b[i]) != (x == c[i])) {
            ok = 0;
        }
    }
    if(ok) {
        c[cnt + 1] = x;
        gao(pos + 1, cnt + 1);   
    }
}

void run(){
    for(int i = 1; i <= n; i++) cin >> a[i];
    for(int i = 1; i <= 4; i++) cin >> b[i];
    for(int i = n; i >= 1; i--) {
        for(int j = 0; j < N; j++) suf[i][j] = suf[i + 1][j];
        ++suf[i][a[i]];   
    }
    gao(0, 0);
    cout << ans << '\n';
}

int main() {
    ios::sync_with_stdio(false);
    cin.tie(0); cout.tie(0);
    cout << fixed << setprecision(20);
    while(cin >> n) run();
    return 0;
}

G. Cryptographically Secure Pseudorandom Number Generator

题意:
给出一个素数\(p\),寻找所有的\(x\)满足:
\[ f(x)=min_{k=2}^{x}f(k) \]
\(f(x)\)满足\(x\cdot f(x)\equiv 1 (mod\ p)\)

思路:
打个表发现具有对称关系。
然后猜一猜,可能只会枚举到根号,直接暴力过去就行了。。。


Code

/*
 * Author:  heyuhhh
 * Created Time:  2020/1/16 21:33:24
 */
#include <iostream>
#include <algorithm>
#include <cstring>
#include <vector>
#include <cmath>
#include <set>
#include <map>
#include <queue>
#include <iomanip>
#define MP make_pair
#define fi first
#define se second
#define sz(x) (int)(x).size()
#define all(x) (x).begin(), (x).end()
#define INF 0x3f3f3f3f
#define Local
#ifdef Local
  #define dbg(args...) do { cout << #args << " -> "; err(args); } while (0)
  void err() { std::cout << '\n'; }
  template<typename T, typename...Args>
  void err(T a, Args...args) { std::cout << a << ' '; err(args...); }
#else
  #define dbg(...)
#endif
void pt() {std::cout << '\n'; }
template<typename T, typename...Args>
void pt(T a, Args...args) {std::cout << a << ' '; pt(args...); }
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
//head
const int N = 1e6 + 5;

int MOD;
int inv[N];

void run(){
    cin >> MOD;
    inv[0] = inv[1] = 1;
    vector <pii> ans;
    int Min = INF;
    for(int i = 2; i < MOD; i++) {
        inv[i] = 1ll * (MOD - MOD / i) * inv[MOD % i] % MOD;
        if(inv[i] <= Min) {
            if(i > inv[i]) break;   
            Min = inv[i];
            ans.push_back(MP(i, inv[i]));   
        }
    }
    vector <pii> res = ans;
    reverse(all(res));
    for(auto it : res) if(it.fi != it.se) ans.push_back(MP(it.se, it.fi));
    cout << sz(ans) << '\n';
    for(auto it : ans) cout << it.fi << ' ' << it.se << '\n';
}

int main() {
    ios::sync_with_stdio(false);
    cin.tie(0); cout.tie(0);
    cout << fixed << setprecision(20);
    int T; cin >> T;
    while(T--) run();
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/heyuhhh/p/12294411.html