H.Visit the Park
题面
思路
首先按照题目意思打了个暴力dfs
;
typedef long long ll;
const int MOD = 998244853;
int qpow(int x,int y){
ll base = x,ret = 1;
while(y){
if(y&1){
ret *= base;
ret %= MOD;
}
base *= base;
base %= MOD;
y >>= 1;
}
return ret;
}
#define int ll
int inv(int x){
return qpow(x,MOD-2);
}
int mul(int x,int y){
return (1ll*(x%MOD)*(y%MOD))%MOD;
}
int add(int x,int y){
return (1ll*(x%MOD)+(y%MOD))%MOD;
}
typedef pair<int,int> pii;
vector<pii> G[N];
int path[N],n,m,k;
map<pii,vector<int>> mp;
int ans;
void dfs(int idx,int val,int inv_sum){
if(idx == k){
ans = add(ans,mul(val,inv(inv_sum)));
return;
}
int u = path[idx];
int v = path[idx + 1];
if(u > v) swap(u,v);
for(auto w : mp[{u,v}]){
dfs(idx+1,add(mul(val,10),w),mul(inv_sum,mp[{u,v}].size()));
}
}
void solve(){
cin >> n >> m >> k;
for(int i=1,u,v,w;i<=m;++i){
cin >> u >> v >> w;
if(u > v) swap(u,v);
mp[{u,v}].push_back(w);
}
for(int i=1;i<=k;++i)
cin >> path[i];
for(int i=1;i<k;++i){
int u = path[i],v = path[i+1];
if(u > v) swap(u,v);
if(mp[{u,v}].size() == 0){
cout << "Stupid Msacywy!\n";
return;
}
}
//保证有解
dfs(1,0,1);
cout << ans << '\n';
}
然后愉快的TLE
了;
假设路径上的数字是 789 789 789;
暴力统计的话是
sum = sum * 10 + w //数字总和
inv = inv * (u,v)的路径数量 //概率
我们可以用分配律来优化;
因为 ( 1 , 2 ) (1,2) (1,2)之间的边都是乘 100 100 100这个数量级,然后 ( 2 , 3 ) (2,3) (2,3)之间的边都是乘 10 10 10这个数量级, ( 3 , 4 ) (3,4) (3,4)之间的边都是乘 1 1 1这个数量级;
因此我们就可以一次性统计完任意两点之间产生的贡献;
伪代码如下
//从最高数量级开始
for(int i=1;i<k-1;++i) times *= 10;
for(int i=1;i<k;++i){
int u = path[i],v = path[i+1];
auto ve = (u,v)两点之间边权集合
int inv_sz = inv(ve.size());
//一次性统计(u,v)所有路径产生的贡献
for(auto w : ve){
ans = ans + times * w * inv_sz
}
times /= 10;//降低数量级
}
Code
#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
#include <vector>
#include <utility>
#include <map>
using namespace std;
typedef long long ll;
const int N = 3e5 + 10;
const int MOD = 998244853;
int qpow(int x,int y){
ll base = x,ret = 1;
while(y){
if(y&1){
ret *= base;
ret %= MOD;
}
base *= base;
base %= MOD;
y >>= 1;
}
return ret;
}
#define int ll
int inv(int x){
return qpow(x,MOD-2);
}
int mul(int x,int y){
return (1ll*(x%MOD)*(y%MOD))%MOD;
}
int add(int x,int y){
return (1ll*(x%MOD)+(y%MOD))%MOD;
}
typedef pair<int,int> pii;
int path[N],n,m,k;
map<pii,vector<int>> mp;
int ans;
void solve(){
int inv10 = inv(10);
cin >> n >> m >> k;
for(int i=1,u,v,w;i<=m;++i){
cin >> u >> v >> w;
if(u > v) swap(u,v);
mp[{u,v}].push_back(w);
}
for(int i=1;i<=k;++i)
cin >> path[i];
for(int i=1;i<k;++i){
int u = path[i],v = path[i+1];
if(u > v) swap(u,v);
if(mp[{u,v}].size() == 0){
cout << "Stupid Msacywy!\n";
return;
}
}
//保证有解
//使用分配律优化
int times = 1;
for(int i=1;i<k-1;++i) times = mul(times,10);
for(int i=1;i<k;++i){
int u = path[i],v = path[i+1];
if(u > v) swap(u,v);
auto ve = mp[{u,v}];
int inv_sz = inv(ve.size());
for(auto w : ve){
//ans = ans + times * w * inv_sz
ans = add(ans,mul(times,mul(w,inv_sz)));
}
times = mul(times,inv10);
}
cout << ans << '\n';
}
signed main(){
std::ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
solve();
return 0;
}
K. Bracket Sequence
题面
思路
不知道卡特兰数列是什么戳这;
Code
#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
using namespace std;
typedef long long ll;
const int N = 2e5 + 10;
const int MOD = 1e9 + 7;
#define int ll
int qpow(int x,int y){
ll base = x,ret = 1;
while(y){
if(y&1) ret = ret * base % MOD;
base = base * base % MOD;
y >>= 1;
}
return ret;
}
ll fact[N];
ll inv_fact[N];
void init(){
fact[0] = inv_fact[0] = 1;
for(int i=1,inv;i<N;++i){
fact[i] = (fact[i-1] * i) % MOD;
inv = qpow(i,MOD-2);
inv_fact[i] = (inv_fact[i-1] * inv) % MOD;
}
}
//C_a ^ b
int C(int a,int b){
return ((fact[a] * inv_fact[b])%MOD
* inv_fact[a-b])%MOD;
}
void solve(){
init();
int n,k;
cin >> n >> k;
ll one = ((C(2*n,n) - C(2*n,n-1))%MOD+MOD)%MOD;
ll two = qpow(k,n);
int ans = (((one%MOD)*(two%MOD)%MOD)+MOD)%MOD;
cout << ans << '\n';
}
signed main(){
std::ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
solve();
return 0;
}