最开始想的暴力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. idea中tomcat乱码问题解决

    在idea中经常遇到jsp的乱码问题,原因是编码不是UTF-8的问题,这次来彻底解决idea的编码问题 首先设置idea编辑器的编码: File-Setting设置如下 然后配置tomcat的编码问题 ...

  2. centos6.5 导入matplotlib报错 No module named '_tkinter

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

  3. wordpress 模板制作之一

    WP模板工作原理图:

  4. 深入理解Spring之九:DispatcherServlet初始化源码分析

    转载 https://mp.weixin.qq.com/s/UF9s52CBzEDmD0bwMfFw9A DispatcherServlet是SpringMVC的核心分发器,它实现了请求分发,是处理请 ...

  5. flask插件系列之flask_celery异步任务神器

    现在继续学习在集成的框架中如何使用celery. 在Flask中使用celery 在Flask中集成celery需要做到两点: 创建celery的实例对象的名字必须是flask应用程序app的名字,否 ...

  6. juery给所有ID属性相同的div绑定一个事件

    案例: <div id="div1">内容</div> <div id="div1">内容</div> < ...

  7. Spring是什么+控制反转和依赖注入

    Spring是一个开源框架,是一个轻量级的控制反转(IOC)和面向切面(AOP)的容器框架. 原因: (1)通过控制反转(IOC)达到松耦合,IOC也就是把控制权交出去,在使用中直接得到对象 (2)提 ...

  8. cocos2d-x android 添加新场景报错: undefined reference to `vtable for XXX'

    转载自 居家懒人 http://www.cnblogs.com/JD85/archive/2012/09/17/2688128.html 加入写了新场景SecondScene,结果在cpp文件里类名地 ...

  9. tftp 开发板ping不通PC机

    开发板:JZ2440(天下2440开发板是一家) 当进入uboot界面时:输入命令print则显示: 将PC端的IP设置为192.168.1.11 在开发板上ping   192.168.1.11,若 ...

  10. php 高并发解决方案(用于抢购) 转载

    最近在做一个团购项目,遇到个问题,就是在抢购.秒杀.抽奖等活动时,库存数量有限,但是同时下单人数超过了库存数量,就会导致商品超售问题.那么我们怎么来解决这个问题呢,我的思路如下: sql1:查询商品库 ...