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(l−1) 即可。
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,细节题)
2019ICPC南昌邀请赛现场赛A题 - Attack(斯坦纳树)