最开始想的暴力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. centos6.5 导入matplotlib报错 No module named '_tkinter

    1.解决方案 在centos系统下,导入matplotlib时,出现ImportError: No module named ‘_tkinter’的错误,首先 yum list installed | ...

  2. [整理] magento搬家

    将原来网站文件中的var文件中的cache和session文件删除,将media中的缓存文件删除.然后将所有文件制作成一个压缩包,以减少文件体积,方便转移. 将压缩包转移到新的服务器域名指向的文件夹, ...

  3. bzoj 3522 tree-dp 暴力

    首先我们知道,这个题可以N^2的做,我们先确定一个根,然后讨论下情况,合法的三个点只可能有三种情况,第一种是三个点有相同的lca,这种情况我们可以用tree-dp来解决,用dis[i][j]表示i为根 ...

  4. 飘雪效果的swf

    //第一帧动作 import flash.events.Event; ;k<;k++) { var xuehua:xue= new xue(); xuehua.alpha = Math.rand ...

  5. perf + 火焰图分析程序性能

    1.perf命令简要介绍 性能调优时,我们通常需要分析查找到程序百分比高的热点代码片段,这便需要使用 perf record 记录单个函数级别的统计信息,并使用 perf report 来显示统计结果 ...

  6. Python3 断言

    #!/usr/bin/env python # _*_ coding:utf-8 _*_ # Author:CarsonLi ''' 断言一般用于后面有非常重要的操作,需要使用前面的数据,而且不容许出 ...

  7. MySQL数据库的“十宗罪”【转】

    今天就给大家列举 MySQL 数据库中最经典的十大错误案例,并附有处理问题的解决思路和方法.希望能给刚入行或数据库爱好者一些帮助,今后再遇到任何报错,我们都可以很淡定地去处理.学习任何一门技术的同时, ...

  8. Python多态、鸭子类型

    一.多态 多态指的是一类事物有多种形态. 动物有多种形态:人,狗,猪 import abc class Animal(metaclass=abc.ABCMeta): #同一类事物:动物 @abc.ab ...

  9. Selenium_Page Object设计模式

    Page Object 介绍 Page Object设计模式的优点如下: 减少代码的重复 提高测试用例的可读性 提高测试用例的可维护性,特别是针对UI频繁变化的项目 当Web页面编写测试时,需要操作该 ...

  10. ISSCC 2017论文导读 Session 14 Deep Learning Processors,DNPU: An 8.1TOPS/W Reconfigurable CNN-RNN

    转载请注明,本文出自Bin的专栏http://blog.csdn.net/xbinworld,谢谢! DNPU: An 8.1TOPS/W Reconfigurable CNN-RNN Process ...