最开始想的暴力DP是把天数作为一个维度所以怎么都没有办法优化,矩阵快速幂也是$O(n^3)$会爆炸。

但是没有想到另一个转移方程:定义$f[i][j]$表示每天都有值的$i$天,共消费出总值$j$的方案数。然后答案就是

所以每次维护前缀和就可以$O(1)$转移了。

注意前缀和的初值。

#include<bits/stdc++.h>
#define LL long long
#define mod 998244353
using namespace std; int n, m;
LL d;
LL dp[][], sum[][]; LL mpow(LL a, LL b) {
LL ans = ;
for(; b; b >>= , a = a * a % mod)
if(b & ) ans = ans * a % mod;
return ans;
} LL rev(LL a) {
return mpow(a, mod - );
} LL comb(LL p, int q) {
LL a = , b = ;
for(LL i = p - q + ; i <= p; i ++)
a = i % mod * a % mod;
for(int i = ; i <= q; i ++)
b = b * i % mod;
LL ans = a * rev(b) % mod;
return ans;
} int main() {
freopen("contract.in", "r", stdin);
freopen("contract.out", "w", stdout);
while(cin >> n >> d >> m) {
if(n == && d == && m == ) break;
d %= mod;
int now = ;
memset(sum, , sizeof(sum));
memset(dp, , sizeof(dp));
for(int i = ; i < m && i <= n; i ++)
dp[][i] = ;
for(int i = ; i <= n; i ++)
sum[][i] = sum[][i-] + dp[][i];
for(int i = ; i <= n && i <= d; i ++) {
for(int j = ; j <= n; j ++) {
if(j - m > ) dp[i][j] = (sum[i-][j-] - sum[i-][j-m] + mod) % mod;
else dp[i][j] = sum[i-][j-];
sum[i][j] = (sum[i][j-] + dp[i][j]) % mod;
}
}
LL ans = ;
for(int i = ; i <= n && i <= d; i ++) {
LL tmp = comb(d, i);
ans = (ans + tmp * dp[i][n] % mod) % mod;
}
printf("%lld\n", ans);
}
return ;
}

起点确定的最小环。

我们可以发现,因为环的起点和终点都是1,所以题目实际是找与1相连的一个起点和一个终点(因为要保证没有走重边,所以起点和终点一定不同),而对于两个不同的数,二进制位上一定有至少一位不相同,所以可以按每一位,将二进制中当前位不同的点分成两组,代表当前起点和终点,每次跑一遍多起点多终点的$Spfa$,统计最小答案即可。

【注意】不能把每次跑完得到的起点终点直接两两配对,因为两点不一定能相互到达,还是应该在$Spfa$中赋初值跑完。

#include<bits/stdc++.h>
#define oo 0x3f3f3f3f
using namespace std; int n, m, tot; struct Node {
int u, v, nex, w;
Node(int u = , int v = , int nex = , int w = ) :
u(u), v(v), nex(nex), w(w) { }
} Edge[]; int stot, h[];
void add(int u, int v, int s) {
Edge[++stot] = Node(u, v, h[u], s);
h[u] = stot;
} int vis[], dis[], S[], T[], nums, numt, W[], rt[];
queue < int > q;
void Spfa() {
memset(vis, , sizeof(vis));
memset(dis, 0x3f3f3f3f, sizeof(dis));
for(int i = ; i <= nums; i ++) q.push(S[i]), vis[S[i]] = , dis[S[i]] = W[S[i]];
while(!q.empty()) {
int x = q.front(); q.pop(); vis[x] = ;
for(int i = h[x]; i; i = Edge[i].nex) {
int v = Edge[i].v;
if(dis[v] > dis[x] + Edge[i].w && v != ) {
dis[v] = dis[x] + Edge[i].w;
if(!vis[v]) {
vis[v] = ; q.push(v);
}
}
}
}
} int main() {
freopen("leave.in", "r", stdin);
freopen("leave.out", "w", stdout);
int t;
scanf("%d", &t);
while(t --) {
scanf("%d%d", &n, &m);
stot = , tot = ;
memset(h, , sizeof(h));
memset(W, , sizeof(W));
memset(rt, , sizeof(rt));
int ans = 0x3f3f3f3f;
for(int i = ; i <= m; i ++) {
int a, b, c;
scanf("%d%d%d", &a, &b, &c);
add(a, b, c); add(b, a, c);
if(b < a) swap(a, b);
if(a == ) rt[++tot] = b, W[b] = c;
}
if(tot <= ) {
printf("-1\n"); continue;
}
sort(rt + , rt + + tot);
int M = rt[tot];
int tmp = ;
while(M) {
memset(S, , sizeof(S));
memset(T, , sizeof(T));
nums = ; numt = ;
int t = M & ;
for(int i = ; i <= tot; i ++)
if(((rt[i] >> tmp) & ) == t) S[++nums] = rt[i];
else T[++numt] = rt[i];
Spfa();
for(int i = ; i <= numt; i ++)
ans = min(ans, W[T[i]] + dis[T[i]]);
M >>= ; tmp ++;
}
if(ans < oo) printf("%d\n", ans);
else printf("-1\n");
}
return ;
}

【10.3校内测试【国庆七天乐!】】【DP+组合数学/容斥】【spfa多起点多终点+二进制分类】的更多相关文章

  1. [CSP-S模拟测试]:多维网格(组合数学+容斥)

    题目传送门(内部题138) 输入格式 输入数据第一行为两个整数$d,n$. 第二行$d$个非负整数$a_1,a_2,...,a_d$.     接下来$n$行,每行$d$个整数,表示一个坏点的坐标.数 ...

  2. 【10.4校内测试】【轮廓线DP】【中国剩余定理】【Trie树+博弈】

    考场上几乎是一看就看出来轮廓线叻...可是调了两个小时打死也过不了手出样例!std发下来一对,特判对的啊,转移对的啊,$dp$数组竟然没有取max!!! 某位考生当场死亡. 结果下午又请了诸位dala ...

  3. 青云的机房组网方案(简单+普通+困难)(虚树+树形DP+容斥)

    题目链接 1.对于简单的版本n<=500, ai<=50 直接暴力枚举两个点x,y,dfs求x与y的距离. 2.对于普通难度n<=10000,ai<=500 普通难度解法挺多 ...

  4. 【10.31校内测试】【组合数学】【记忆化搜索/DP】【多起点多终点二进制拆位Spfa】

    Solution 注意取模!!! Code #include<bits/stdc++.h> #define mod 1000000007 #define LL long long usin ...

  5. bzoj3622已经没有什么好害怕的了 dp+组合+容斥(?)

    3622: 已经没有什么好害怕的了 Time Limit: 10 Sec  Memory Limit: 256 MBSubmit: 1033  Solved: 480[Submit][Status][ ...

  6. 洛谷P4859 已经没有什么好害怕的了 [DP,容斥]

    传送门 思路 大佬都说这是套路题--嘤嘤嘤我又被吊打了\(Q\omega Q\) 显然,这题是要\(DP\)的. 首先思考一下性质: 为了方便,下面令\(k=\frac{n+k}{2}\),即有恰好\ ...

  7. loj#2542. 「PKUWC2018」随机游走(树形dp+Min-Max容斥)

    传送门 首先,关于\(Min-Max\)容斥 设\(S\)为一个点的集合,每个点的权值为走到这个点的期望时间,则\(Max(S)\)即为走遍这个集合所有点的期望时间,\(Min(S)\)即为第一次走到 ...

  8. LOJ3102. 「JSOI2019」神经网络 [DP,容斥,生成函数]

    传送门 思路 大部分是感性理解,不保证完全正确. 不能算是神仙题,但我还是不会qwq 这题显然就是求:把每一棵树分成若干条链,然后把链拼成一个环,使得相邻的链不来自同一棵树,的方案数.(我才不告诉你们 ...

  9. [CSP-S模拟测试]:建设城市(city)(组合数学+容斥)

    题目传送门(内部题8) 输入格式 一行三个整数$n,m,k$. 输出格式 一行一个整数表示答案.对$998244353$取模. 样例 样例输入 3 7 3 样例输出 数据范围与提示 对于10%的数据, ...

随机推荐

  1. 2017ACM暑期多校联合训练 - Team 1 1003 HDU 6035 Colorful Tree (dfs)

    题目链接 Problem Description There is a tree with n nodes, each of which has a type of color represented ...

  2. 爬虫--PyQuery

    什么是PyQuery? PyQuery 初始化 字符串初始化 from pyquery import PyQuery as pq html=""" <div> ...

  3. 【译】第三篇 SQL Server代理警报和操作员

    本篇文章是SQL Server代理系列的第三篇,详细内容请参考原文. 正如这一系列的上一篇所述,SQL Server代理作业是由一系列的作业步骤组成,每个步骤由一个独立的类型去执行,除了步骤中执行的工 ...

  4. WAMP允许外部访问的修改方法

    apache配置文件httpd.conf里的 "Require local"改" Require all granted"

  5. spring boot 自定义属性覆盖application文件属性

    参考 Spring boot源码分析-ApplicationListener应用环境: https://blog.csdn.net/jamet/article/details/78042486 加载a ...

  6. HMM的概述(五个基本元素、两个假设、三个解决的问题)

    一.五个基本元素 HMM是个五元组 λ =( S, O , π ,A,B) S:状态值集合,O:观察值集合,π:初始化概率,A:状态转移概率矩阵,B:给定状态下,观察值概率矩阵   二.两个假设 HM ...

  7. android sdcard 权限管理策略研究

    自从android4.4 以来,第三方应用程序是不能再随便的访问sdcard了,从开发者的角度而言,研究一下android系统到底是怎么样来实现这样的控制还是比较有价值的. 首先分析下现状,现在已知, ...

  8. 516.Longest Palindromic subsequence---dp

    题目链接:https://leetcode.com/problems/longest-palindromic-subsequence/description/ 题目大意:找出最长回文子序列(不连续), ...

  9. Linux软件管理器(如何使用软件管理器来管理软件)2---安装及管理Linux应用程序

    安装及管理Linux应用程序 Linux应用程序的组成1.普通的可执行程序文件,一般保存在/usr/bin目录中,普通用户即可执行.2.服务器程序.管理程序文件,一般保存在/usr/sbin目录中,需 ...

  10. Dagger:快速的依赖注入for 安卓&Java

    Dagger:快速的依赖注入for 安卓&Java 2014年5月8日 星期四 15:29 官网: http://square.github.io/dagger/ GitHub: https: ...