2019 ACM - ICPC 全国邀请赛(南昌) 题解(9 / 12)

Posted 繁凡さん

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了2019 ACM - ICPC 全国邀请赛(南昌) 题解(9 / 12)相关的知识,希望对你有一定的参考价值。

整理的算法模板合集: ACM模板

点我看算法全家桶系列!!!

实际上是一个全新的精炼模板整合计划


The 2019 ICPC China Nanchang National Invitational and International Silk-Road Programming Contest

VP地址:https://www.jisuanke.com/contest/20996/challenges

A. Attack

Solution

斯坦纳树板子 + DP即可

Code

#include <bits/stdc++.h>
using namespace std;

const int inf = 0x3f3f3f3f;
const int M = 2e3 + 10;
const int N = 40;

struct Edge{
	int to,val;
	int nxt;
}edges[M];
int head[N],idx = 0;
void add(int u, int v, int c)
{
	edges[idx] = {v,c,head[u]}, head[u] = idx++;
	edges[idx] = {u,c,head[v]}, head[v] = idx++;
}

int dp[N][500];
int f[500];
map<string, int> mp;
typedef pair<int,int> pii;
priority_queue<pii, vector<pii>, greater<pii>> q;
bool vis[N];

void dij(int s)
{
	memset(vis,0,sizeof(vis));
	while(q.size()){
		int u = q.top().second;
		q.pop();
		if(vis[u]) continue;
		vis[u] = 1;
		for(int i = head[u];~i;i = edges[i].nxt){
			int v = edges[i].to;
			int cost = edges[i].val;
			if(dp[v][s] > dp[u][s] + cost){
				dp[v][s] = dp[u][s] + cost;
				q.push({dp[v][s],v});
			}
		}
	}
}

bool check(int s)
{
	for(int i = 0;i < 4;++i){
		int x = s >> (i * 2) & 1;
		int y = s >> (i * 2 + 1) & 1;
		if(x ^ y) return 1;
	}
	return 0;
}

int main()
{
	memset(head,-1,sizeof(head));
	int n,m;
	scanf("%d%d",&n,&m);
	for(int i = 1;i <= n;++i){
		string s;
		cin >> s;
		mp[s] = i;
	}
	for(int i = 0;i < m;++i){
		string a, b;
		int cost;
		cin >> a >> b >> cost;
		add(mp[a],mp[b],cost);
	}
	memset(dp,0x3f,sizeof(dp));
	for(int i = 0;i < 8;++i) {
		string s;
		cin>>s;
		dp[mp[s]][1 << i] = 0;
	}

	for(int s = 0; s < (1 << 8);++s){
		for(int i = 1;i <= n;++i){
			for(int subs = s & (s-1);subs;subs = s & (subs - 1)){
				dp[i][s] = min(dp[i][s], dp[i][subs] + dp[i][s ^ subs]);
			}
			if(dp[i][s] != inf) q.push({dp[i][s],i});
		}
		dij(s);
	}

	memset(f,0x3f,sizeof(f));
	for(int s = 0;s < (1 << 8);++s){
		if(check(s)) continue;
		for(int i = 1;i <= n;++i) f[s] = min(dp[i][s],f[s]);
		for(int subs = s & (s-1);subs;subs = s & (subs - 1)){
			if(check(subs)) continue;
			f[s] = min(f[subs] + f[s ^ subs], f[s]);	
		}
	}
	printf("%d\\n",f[(1 << 8) - 1]);  
	return 0;
}

B. Polynomial

Solution

显然考虑前缀和计算。我们知道若 f f f 是一个 n n n 次多项式,其前缀和 s u m sum sum 是一个 n + 1 n+1 n+1 次多项式,我们已经有了 n + 1 n+1 n+1 个点,先拉格朗日插值求出第 n + 2 n+2 n+2 个点 f ( n + 1 ) f(n+1) f(n+1),然后用这 n + 2 n+2 n+2 个点拉格朗日插值求出 s u m ( r ) , s u m ( l − 1 ) sum(r),sum(l-1) sum(r),sum(l1) 即可。

Code

#include <bits/stdc++.h>

using namespace std;
#define int long long
const int mod = 9999991, N = 5007;

int n, m;
int f[N];
int sum[N];
int fact[mod + 10], infact[mod + 10];
int inv[mod + 10];

int qpow(int a, int b)
{
	int res = 1;
	a %= mod;
	while(b) {
		if(b & 1) res = res * a % mod;
		a = a * a % mod;
		b >>= 1;
	}
	return res;
}
 
void init(int k)
{
	inv[1] = 1;
	for(int i = 2; i <= k; ++ i)
		inv[i] = (mod - mod / i) * inv[mod % i] % mod;
	infact[0] = 1;
	for(int i = 1; i <= k; ++ i) {
		infact[i] = infact[i - 1] * inv[i] % mod;
	}
	//cout << infact[k] << endl; 
}  


int lagrange(int k, int *a, int n)
{
	int up = 1;
	for(int i = 0; i <= n; ++ i) {
		up = up * (k - i) % mod;
	}
	//cout << up << "up" << endl;
	int ans = 0;
	for(int i = 0; i <= n; ++ i) {
		int f;
		if((n - i) & 1) f = -1;
		else f = 1;
		int tmp = a[i] * f * infact[i] % mod * infact[n - i] % mod * (up * inv[k - i] % mod) % mod;
//		cout << infact[i] << endl;
		cout << ans << "ans" << endl;
		ans = ((ans + tmp) % mod + mod) % mod;
	}
	return ans;
}

signed main()
{
	init(mod + 7);
	int t;
	scanf("%lld", &t);
	while(t -- ) {
		scanf("%lld%lld", &n, &m);
		for(int i = 0; i <= n; ++ i) {
			scanf("%lld", &f[i]);
		}
		f[n + 1] = lagrange(n + 1, f, n);
		 
		sum[0] = f[0];
		for(int i = 1; i <= n + 1; ++ i) {
			sum[i] = (sum[i - 1] + f[i]) % mod;
		}
		while(m -- ) {
			int l, r;
			scanf("%lld%lld", &l, &r);

			if(l <= n && r <= n) {
				printf("%lld\\n", (sum[r] - sum[l - 1] + mod) % mod);
			}
			else if(l <= n) {
				printf("%lld\\n", (lagrange(r, sum, n + 1) - sum[l - 1] + mod) % mod);
			}
			else printf("%lld\\n", (lagrange(r, sum, n + 1) - lagrange(l - 1, sum, n + 1) + mod) % mod);
		}
	}
	return 0;
}

C. Xyjj’s sequence

Solution

先欧拉降幂算出权值(数塔),然后直接DP即可。

Code

#include <bits/stdc++.h>

using namespace std;
#define int long long
const int N = 1e5 + 10, p = 1e5 + 3;

int v;
int aw[N], bw[N];
int n, m;
int phi[N];

int a, b;
int primes[N], cnt;
bool vis[N];

int qpow(int a, int b, int mod)
{
	int res = 1;
	a %= mod;
	while(b) {
		if(b & 1) res = res * a % mod;
		a = a * a % mod;
		b >>= 1;
	}
	return res;
}

void init(int n)
{
    phi[1] = 1;
    for(int i = 2; i <= n; ++ i) {
        if(vis[i] == 0) primes[ ++ cnt] = i, phi[i] = i - 1;
        for(int j = 1; j <= cnt && i * primes[j] <= n; ++ j) {
            vis[i * primes[j]] = true;
            if(i % primes[j] == 0) {
                phi[i * primes[j]] = phi[i] * primes[j];
                break;
            }
            phi[i * primes[j]] = phi[i] * (primes[j] - 1);
        }
    }
}

int dp[2][5001][2];


int tower(int num, int p)
{
	if(p == 1) return 0;
	if(num == 1) return b % p;
	return qpow(b, tower(num - 1, phi[p]) + phi[p]以上是关于2019 ACM - ICPC 全国邀请赛(南昌) 题解(9 / 12)的主要内容,如果未能解决你的问题,请参考以下文章

2019 ICPC全国邀请赛(西安)I. Cracking Password(序列检验,BSGS,细节题)

2019 ICPC南昌邀请赛比赛过程及题解

2019ICPC南昌邀请赛现场赛A题 - Attack(斯坦纳树)

ACM-ICPC 2018全国邀请赛(陕西西安)

ACM-ICPC 2019南昌网络赛I题 Yukino With Subinterval

2013ACM-ICPC杭州赛区全国邀请赛——Random Walk