Codeforces Round 856 (Div. 2)

发布时间 2023-03-27 18:02:39作者: wzx_believer

https://codeforces.com/contest/1794

C. Scoring Subsequences

分析:

发现每次前i个的最优答案一定是从后往前连乘的一段 分母依次可以考虑为1 2 3 4。。。(也就是n-i+1)

从后往前考虑

发现只要当前a[i]的>=n-i+1 对答案一定会造成贡献 因为分子/分母>=1

因为分子依次减小(或者不变) 分母依次增大 所以可以二分找到临界点

#include<bits/stdc++.h>
using namespace std;
#define lowbit(x) x&(-x)
const int maxn=1e5+5;
#define ll long long
int n,mid,l,r; 
int a[maxn];
void solve();
int main(){
	int T;cin>>T;
	while(T--)solve();
     return 0;
}
void solve(){
    scanf("%d",&n);
	for(int i=1;i<=n;i++){
		scanf("%d",&a[i]);
		l=1,r=i,mid=l+r>>1;
		while(l<r){
			mid=l+r>>1;
			if(a[mid]>i-mid+1)r=mid-1;
			else if(a[mid]==i-mid+1)l=r=mid;
			else l=mid+1;
		}
		if(a[l]<i-l+1)l++;
		printf("%d ",i-l+1);
	}
	printf("\n");
}
 

D. Counting Factorizations

分析

显然每个质数只能在底数中出现最多一次,在指数中可以出现多次.

设计dp状态 dp[i,j]表示已经处理了前i种数字 并且选择了j种数字作为底数

设前i种数字总共有sum个

考虑当前转移 数字x 有数量y个

如果x不是质数(只能当做指数) dp[i,j]+=dp[i-1,j]*C(n-(sum-j),y)

解释:需要将y个数字放入指数中 已经放了sum-j个指数(总共sum个数 有j个放底数 剩下的sum-j放指数) 总共有n个指数位置 所以C(n-(sum-j),y)

如果x是质数(可以当做指数) dp[i,j]+=dp[i-1,j-1]*C(n-(sum-(j-1)),y-1) 转移同理

代码细节 必须要预处理逆元 否则每次算的话是会超时的

但是有数字范围很大 怎么办 实际上逆元只需要处理阶乘的逆元即可 因为我们算的话只会用到阶乘的逆元

#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int maxn = 1e6 + 5, mod = 998244353;
bool isPrime[maxn];
int primes[maxn], cnt;
ll jc[maxn],dp[maxn],ndp[maxn],ni[maxn];
map<int, int> mp;
map<int,int>::iterator it;
ll fast_mi(ll a ,ll b){
	ll res=1;
	while(b){
		if(b&1)res=res*a%mod;
		b>>=1;
		a=a*a%mod;
	}
	return res;
}	
void init(){
    isPrime[1] = 1;
    for(int i = 2; i < maxn; i++){
        if (!isPrime[i]) primes[cnt++] = i;
        for(int j = 0; i * primes[j] < maxn; j++){
            isPrime[i * primes[j]] = 1;
            if (i % primes[j] == 0) break;
        }
    }
    jc[0]=1;ni[0]=1;
    for(int i=1;i<maxn;i++)jc[i]=jc[i-1]*i%mod,ni[i]=fast_mi(jc[i],mod-2);
}

ll C(int n,int r){
	return jc[n]*ni[r]%mod*ni[n-r]%mod; 
}
int main(){
    init();
    int n;
    cin >> n;
    for(int i = 1; i <= 2 * n; i++){
        int x;
        cin >> x;
        mp[x]++;
    }
    int sum = 0;
    dp[0] = 1;
    for(it=mp.begin();it!=mp.end();it++){
       int val=it->first,num=it->second;
       memset(ndp,0,sizeof(ndp));
        for(int i = 0; i <= n; i++){
            ndp[i] =(ndp[i]+ dp[i] * C(n - (sum - i), num)%mod)%mod;
            if (i >= 1 && !isPrime[val]) ndp[i] =(ndp[i]+ dp[i - 1] * C(n - (sum - i + 1), num- 1)%mod)%mod;
        }
        for(int i=0;i<=n;i++)dp[i]=ndp[i];
        sum += num;
    }
    cout << dp[n] << '\n';

}

E. Labeling the Tree with Distances

分析:

#include<iostream>
#include<cstring>
#include<random>
#include<map>
#include<set>
using namespace std;
using LL = long long;
using ULL = unsigned long long;
const int maxn = 2e5 + 5;
static const ULL mod = (1ull << 61) - 1;
ULL power[maxn];
mt19937_64 rnd(random_device{}());
uniform_int_distribution<ULL> dist(100, mod - 1);
const ULL base = dist(rnd);

static inline ULL add(ULL a, ULL b){
    a += b;
    if (a >= mod) a -= mod;
    return a;
}

static inline ULL mul(ULL a, ULL b){
    __uint128_t c = __uint128_t(a) * b;
    return add(c >> 61, c & mod);
}

void init(){
    power[0] = 1;
    for(int i = 1; i < maxn; i++)
        power[i] = mul(power[i - 1], base);
}

vector<int> g[maxn];
ULL f1[maxn], f2[maxn];

void dfs1(int u, int fa){
    f1[u] = power[0];
    for(auto j : g[u]){
        if (j == fa) continue;
        dfs1(j, u);
        f1[u] = add(f1[u], mul(f1[j], base));
    }
}

void dfs2(int u, int fa, ULL pre){
    f2[u] = add(f1[u], mul(pre, base));
    for(auto j : g[u]){
        if (j == fa) continue;
        dfs2(j, u, add(f2[u], mod - mul(f1[j], base)));
    }
}

int main(){

    cin.tie(0);
    cout.tie(0);
    ios::sync_with_stdio(0);

    init();
    int n;
    cin >> n;
    ULL hsh = 0;
    for(int i = 0; i < n - 1; i++){
        int x;
        cin >> x;
        hsh = add(hsh, power[x]);
    }
    for(int i = 0; i < n - 1; i++){
        int a, b;
        cin >> a >> b;
        g[a].push_back(b);
        g[b].push_back(a);
    }
    dfs1(1, -1);
    dfs2(1, -1, 0);

    set<ULL> target;
    for(int i = 0; i < n; i++)
        target.insert(add(hsh, power[i]));
        
    vector<int> ans;
    for(int i = 1; i <= n; i++){
        if (target.contains(f2[i])){
            ans.push_back(i);
        }
    }
    cout << ans.size() << '\n';
    for(auto x : ans) cout << x << ' ';
    cout << '\n';

}