B. A Funny Bipartite Graph

状压 dp ,利用了原题中选完左边点集,那么右边在 左边编号最大的那个数 之前的所有点都要选的性质,可以优化到 \(O(n \cdot 2^n)\)。由于懒得补,所以写个算法溜了。(逃

C. And and Pair

题目大意:给你一个数 n 的二进制表示。你需要找出小于 n 有多少二元组 (i,j) 满足以下条件。

\[0\leq j \leq i \leq n
\]
\[i \& n = i
\]
\[i \& j = 0
\]

做法:后两个条件告诉我们, i 要在n二进制数为 1 的位置上选是 1 or 0,j 要在 n 二进制数为 0 的位置上选是 1 or 0。 i,j 其余位置全为 0。(接下来全是二进制表示)我们枚举 i 中是 1 的最高位,这样我们就发现后面的所有数可以在没有前导零这个问题困扰下,去取最高位后面的数。

设取到当前这一位后面 0 的个数有 a 个,1 的个数有 b 个,i 中 1 的个数为 c \((0 \leq c \leq b)\) ,则 j 有 \(2^{|S|-c}\) 种选法(|S|为当前枚举到的长度),i 中 1 的个数为 c 有 \(C_b^c\) 个。

那么,当前这一位(假如是 1 )的答案为:

\[ans = \sum_{c=0}^b C_b^c 2^{|S|-c}1^c = 2^{|S|-b}(\sum_{c=0}^b C_b^c 1^c 2^{b-c}) = 3^b 2^{|S|-b} = 3^b 2^a
\]

最后把 ans 全加起来就行了。由于你是考虑最高位为 1 这样考虑的,所以还有一个 i = 0 需要特意加一个 1 。意识流下划线代码:

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define IL inline
#define ri register int
typedef long long LL; const int N = 1e5 + 3;
const int mod = 1e9 + 7;
char s[N];
int _2[N],_3[N]; int main() {
int T; scanf("%d",&T);
_2[0] = _3[0] = 1;
for(int i=1;i<=1e5;i++) {
_2[i] = 2LL * _2[i-1] % mod;
_3[i] = 3LL * _3[i-1] % mod;
}
while(T--) {
scanf("%s",s);
int len = strlen(s);
int ans, _0, _1;
ans = _0 = _1 = 0;
for(int i=len-1;i>=0;i--) {
if(s[i] == '1') {
ans = (ans + 1LL*_2[_0]*_3[_1]%mod) % mod;
_1++;
}
else _0++;
}
ans = (ans + 1) % mod;
printf("%d\n",ans);
}
}

队友代码:(他说用了 dp ,但是我不知道 dp 咋做。)

#include <bits/stdc++.h>

using namespace std;

const int MOD = 1e9 + 7;

char s[100005];
int f[100005]; int main() {
int T;
//freopen("1.txt", "r", stdin);
cin >> T;
while (T--) {
scanf("%s", s);
int n = strlen(s);
int lst = 1, ans = 1;
for (int i = n - 1; i >= 0; i--) {
if (s[i] == '0')
(lst <<= 1) %= MOD, f[i] = 0;
else {
f[i] = lst;
lst = (1ll * lst * 2 + f[i]) % MOD;
}
}
for (int i = n - 1; i >= 0; i--)
(ans += f[i]) %= MOD;
printf("%d\n", ans);
}
return 0;
}
E. Bob's Problem

题目大意:给你一张图,有边权,然后每条边可能为白边或者黑边。你需要找到连通整个图的最大边权和,但是你不能选择超过 k 个白边。

做法:最大生成树。你就把黑边全选了,然后对白边套最大生成树做法就行。我在写的时候只记得特判有没有超过 k ,忘了特判原图是否连通了……

#include<cstdio>
#include<cstring>
#include<vector>
#include<algorithm>
using namespace std;
#define IL inline
typedef long long LL; const int N = 50000 + 3;
const int M = 500000 + 3; struct Edge {
int u,v,w,col;
Edge(int u=0,int v=0,int w=0,int col=0):u(u),v(v),w(w),col(col) {}
IL bool operator < (const Edge& rhs) const {
return col < rhs.col || (col == rhs.col && w > rhs.w);
}
}; struct MST {
LL ans;
int n,m,k,bcnt;
int pa[N];
int sz[N];
bool ing[M];
vector<Edge> edges; void init(int n,int m,int k) {
this->n = n; this->m = m; this->k = k;
ans = 0; bcnt = 0;
fill(ing,ing+m,0);
edges.clear();
for(int i=0;i<n;i++) { pa[i] = i; sz[i] = 1;}
} int findset(int x) { return x == pa[x] ? x : pa[x] = findset(pa[x]);}
void merge(int fx,int fy) {
if(sz[fx] <= sz[fy]) {
pa[fx] = fy;
sz[fy] += sz[fx];
}
else {
pa[fy] = fx;
sz[fx] += sz[fy];
}
} IL LL solve() {
int cnt = 0,vcnt = 0;
sort(edges.begin(),edges.end());
for(int i=0;i<bcnt;i++) {
Edge &e = edges[i];
int u = e.u, v = e.v, w = e.w;
int fu = findset(u), fv = findset(v);
if(fu != fv) { merge(fu,fv); vcnt++;}
ans = ans + w;
}
for(int i=bcnt;i<m;i++) {
Edge &e = edges[i];
int u = e.u, v = e.v, w = e.w;
int fu = findset(u), fv = findset(v);
if(fu != fv) {
cnt++; vcnt++;
ing[i] = true;
merge(fu,fv);
ans = ans + w;
}
if(cnt >= k) {
return vcnt == n-1 ? ans : -1;
}
}
for(int i=bcnt;i<m&&cnt<k;i++) {
if(!ing[i]) {
ans = ans + edges[i].w;
cnt++;
ing[i] = true;
}
}
return vcnt == n-1 ? ans : -1;
}
}; MST solver; int main() {
int T; scanf("%d",&T);
while(T--) {
int n,m,k; scanf("%d%d%d",&n,&m,&k);
solver.init(n,m,k);
for(int i=0;i<m;i++) {
int u,v,w,col;
scanf("%d%d%d%d",&u,&v,&w,&col); u--; v--;
solver.edges.push_back(Edge(u,v,w,col));
if(!col) solver.bcnt++;
}
printf("%lld\n",solver.solve());
}
return 0;
}
G. Eating Plan

题意:给你一个长度为 n 的排列,你只能选取连续的一段,获得数值为这一段每一个元素的阶乘之和再对 t 取余。再给你 m 次查询,问你最少选多长的一段,可以使得获得的数值大于等于每次询问给你的数 k。

做法:可以发现 \(t = 998857459 = 461 * 773 * 2803\) ,于是大于 2803 的数的阶乘对 t 取余等于0。那么这个排列的阶乘就变成了一段0,然后一个数,再一段0……如此反复。然后乱搞即可。

附队友代码:

#include <bits/stdc++.h>

using namespace std;

const int MOD = 998857459;

int num[3005];
int pos[3005], t;
int a[100005], sum[100005];
int len[100005]; int main() {
//freopen("1.txt", "r", stdin);
int n, m;
scanf("%d%d", &n, &m);
num[1] = 1;
for (int i = 2; i <= 2803; i++)
num[i] = 1ll * num[i - 1] * i % MOD;
for (int i = 1; i <= n; i++) {
scanf("%d", &a[i]);
if (a[i] >= 2803) a[i] = 0;
else
pos[++t] = i, a[i] = num[a[i]];
}
for (int i = 1; i <= n; i++)
sum[i] = (sum[i - 1] + a[i]) % MOD;
for (int i = 1; i <= t; i++) {
for (int j = i; j <= t; j++) {
int l = pos[i], r = pos[j], ll = pos[i - 1];
len[r - l + 1] = max(len[r - l + 1], ((sum[r] - sum[ll]) % MOD + MOD) % MOD);
}
}
for (int i = 1; i <= n; i++)
len[i] = max(len[i], len[i - 1]);
int k;
for (int i = 1; i <= m; i++) {
scanf("%d", &k);
if (len[n] < k) {
printf("-1\n");
continue;
}
int l = 1, r = n, mid;
while (l < r) {
mid = l + r >> 1;
if (len[mid] >= k)
r = mid;
else l = mid + 1;
}
printf("%d\n", r);
}
return 0;
}
L. Who is the Champion

题意:签到题(我还没搞懂题意啥意思呢,丢个队友代码溜了)

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<string>
#include<cmath>
#include<map>
#include<stack>
#include<vector>
#include<queue>
#include<set>
#include<algorithm>
#define max(a,b) (a>b?a:b)
#define min(a,b) (a<b?a:b)
#define swap(a,b) (a=a+b,b=a-b,a=a-b)
#define memset(x,y) memset(x,y,sizeof(x))
#define ll long long
using namespace std;
int n;
int a[110][110];
struct team {
int num;
int boll;
int s;
} t[110];
bool cmp(team t1,team t2) {
if(t1.s!=t2.s)return t1.s>t2.s;
else return t1.boll>t2.boll;
}
int main() {
//freopen(".in","r",stdin);
//freopen(".out","w",stdout);
cin>>n;
for(int i=1; i<=n; i++) {
for(int j=1; j<=n; j++) {
cin>>a[i][j];
}
}
if(n==1) {
cout<<"1";
return 0;
}
for(int i=1; i<=n; i++) {
t[i].num=i;
for(int j=1; j<=n; j++) {
if(i==j)continue;
if(a[i][j]>a[j][i])t[i].s+=3,t[i].boll+=(a[i][j]-a[j][i]);
else if(a[i][j]==a[j][i])t[i].s+=1;
else t[i].boll+=(a[i][j]-a[j][i]);
}
}
sort(t+1,t+n+1,cmp);
if(t[1].s==t[2].s&&t[1].boll==t[2].boll)cout<<"play-offs";
else cout<<t[1].num;
return 0;
}
M. XOR Sum

题意:设

\[f(i,k) = 1 \oplus 2 \oplus 3 \oplus .. \oplus i^k
\]

给你 t,x,y ,求

\[\sum_{k=1}^t \sum_{i=x}^y f(i,k) \mod (1e9+7)
\]

题解:可以发现

\[f(x) =
\begin{cases}
i^k , i^k \equiv 0 \mod 4\\
1 , i^k \equiv 1 \mod 4\\
i^k+1 , i^k \equiv 2 \mod 4\\
0 , i^k \equiv 3 \mod 4\\
\end{cases}
\]

所以

\[\sum_{k=1}^t \sum_{i=x}^y f(i,k) = \sum_{k=1}^t \sum_{i=x}^y i^k [i^k \mod 2 =0] + \sum_{k=1}^t \sum_{i=x}^y [i^k \mod 4 = 1 \text{ or } 2]
\]

先讨论第二项,因为这个比较好推。当 \(i \equiv 0(\mod 4)\) 时,无论 k 取多少都没有贡献。当 \(i \equiv 1(\mod 4)\) 时,k 可以取任意值,都有贡献。当 \(i \equiv 2(\mod 4)\) 时,k 只能取 1。当 \(i \equiv 3(\mod 4)\) 时,k 只有为偶数时才有贡献。这样第二项就可以 \(O(1)\) 做出来了。

再看第一项

\[\sum_{k=1}^t \sum_{i=x}^y i^k [i^k \mod 2 =0] = \sum_{k=1}^t \sum_{i=\lfloor\frac{x+1}{2}\rfloor}^{\lfloor \frac{y}{2} \rfloor} (2i)^k = \sum_{k=1}^t (\sum_{i=1}^{\lfloor \frac{y}{2} \rfloor} (2i)^k - \sum_{i=1}^{\lfloor\frac{x+1}{2}\rfloor} (2i)^k)
\]

如果使用里面的式子直接对每一个最高 k+1 次方的多项式进行拉格朗日插值,那么时间复杂度会来到 \(O(t^2)\) 。但是经过观察发现,这个式子还是一个最高 t+1 次方的多项式,这样我们可以这么化这个式子。

\[\sum_{k=1}^t \sum_{i=\lfloor\frac{x+1}{2}\rfloor}^{\lfloor \frac{y}{2} \rfloor} (2i)^k = \sum_{i=\lfloor\frac{x+1}{2}\rfloor}^{\lfloor \frac{y}{2} \rfloor} \sum_{k=1}^t (2i)^k = \sum_{i=\lfloor\frac{x+1}{2}\rfloor}^{\lfloor \frac{y}{2} \rfloor} \frac{2i(1-(2i)^t)}{1-2i} \\= \sum_{i=1}^{\lfloor \frac{y}{2} \rfloor} \frac{2i(1-(2i)^t)}{1-2i} - \sum_{i=1}^{\lfloor\frac{x+1}{2}\rfloor} \frac{2i(1-(2i)^t)}{1-2i}
\]

化到这一步,就可以直接对这个式子进行拉格朗日插值了。

#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long LL;
#define IL inline
#define ri register int const int N = 1e5 + 5;
const LL mod = 1e9 + 7; LL jc[N],ijc[N]; LL ksm(LL a,LL b, LL p) {
LL res = 1LL;
while(b) {
if(b&1LL) res = res * a % p;
a = a * a % p;
b >>= 1LL;
}
return res;
} //(0,y0),(1,y1),..,(n,yn) -> (xi,y_xi)
LL pre[N],suf[N];
LL lagrange(int n,LL *y,LL xi) {
if(xi <= n) return y[xi];
pre[0] = xi % mod; suf[n+1] = 1;
for(int i=1;i<=n;i++) pre[i] = (xi-i)%mod*pre[i-1]%mod;
for(int i=n;i>=0;i--) suf[i] = (xi-i)%mod*suf[i+1]%mod;
LL ans = y[0]%mod*suf[1]%mod*ijc[n]%mod;
if(n&1) ans = -ans;
for(int i=1;i<=n;i++) {
LL now = y[i]*pre[i-1]%mod*suf[i+1]%mod*ijc[i]%mod*ijc[n-i]%mod;
if((n-i)&1) ans = (ans - now + mod) % mod;
else ans = (ans + now) % mod;
}
return ans;
} LL calc(LL L, LL R,LL a) {
LL sumR = (R - a + 4) / 4;
LL sumL = (L-1-a + 4) / 4;
return (sumR - sumL + mod) % mod;
} LL t,x,y;
LL S[N]; int main() {
scanf("%lld%lld%lld",&t,&x,&y);
jc[0] = ijc[0] = 1;
for(int i=1;i<N;i++) jc[i] = jc[i-1] * i % mod;
ijc[N-1] = ksm(jc[N-1],mod-2,mod);
for(int i=N-2;i>=0;i--) ijc[i] = (i+1) * ijc[i+1] % mod; S[0] = 0;
for(int i=1;i<=t+1;i++) {
S[i] = ((ksm(2*i,t+1,mod)-2*i+mod) * ksm(2*i-1,mod-2,mod)%mod + S[i-1]) % mod;
} LL ans = (lagrange(t+1,S,y/2) - lagrange(t+1,S,(x+1)/2-1) + mod) % mod;
ans = (ans + calc(x,y,2)) % mod;
ans = (ans + t * calc(x,y,1)) % mod;
ans = (ans + t/2 * calc(x,y,3)) % mod;
printf("%lld\n",ans);
return 0;
}

附:拉格朗日插值公式

给出 n 个不连续的坐标的插值法:

\[f(k) = \sum_{i=0}^n y_i \prod_{i=0,i\not=j}^n \frac{k-x_j}{x_i-x_j}
\]

注:这里 lagrange 函数里的 n 是多项式最高项次数。

#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
using namespace std;
#define IL inline
#define ri register int
const int mod = 998244353; int ksm(int a,int b,int p) {
int res = 1;
while(b) {
if(b&1) res = 1LL * res * a % p;
a = 1LL * a * a % p;
b >>= 1;
}
return res;
} int lagrange(int n,int *x,int *y,int xi) {
int ans = 0;
for(int i=0;i<=n;i++) {
int fz = 1, fm = 1;
for(int j=0;j<=n;j++) if(i != j) {
fz = 1LL * fz * (xi - x[j]) % mod;
fm = 1LL * fm * (x[i]-x[j]) % mod;
}
ans = (ans + 1LL*y[i]*fz%mod*ksm(fm,mod-2,mod) % mod) % mod;
}
return (ans + mod) % mod;
} const int N = 2e3 + 3; int n,m;
int a[N],b[N]; int main() {
scanf("%d%d",&n,&m);
for(int i=0;i<n;i++) scanf("%d%d",&a[i],&b[i]);
printf("%d\n",lagrange(n-1,a,b,m));
return 0;
}

从 0 到 n 这种坐标连续的拉格朗日插值法:

\[pre_i=\prod_{j=0}^i k-j \\ suf_i = \prod_{j=i}^n k-j \\ f(k) = \sum_{i=0}^n y_i \prod_{i=0,i\not=j}^n \frac{k-j}{i-j} = \sum_{i=0}^n y_i \frac{pre_{i-1}\cdot suf_{i+1}}{i! \cdot (n-i)!}
\]

代码直接看上面的 M 题即可。

这些代码都是从 0 开始存的,且 n 为多项式最高次幂次数。

2019 南昌区域赛 CEGLM 题解 & lagrange 插值的更多相关文章

  1. 2019南昌网络赛I:Yukino With Subinterval(CDQ) (树状数组套主席树)

    题意:询问区间有多少个连续的段,而且这段的颜色在[L,R]才算贡献,每段贡献是1. 有单点修改和区间查询. 思路:46min交了第一发树套树,T了. 稍加优化多交几次就过了. 不难想到,除了L这个点, ...

  2. ACM-ICPC 2019南昌网络赛I题 Yukino With Subinterval

    ACM-ICPC 2019南昌网络赛I题 Yukino With Subinterval 题目大意:给一个长度为n,值域为[1, n]的序列{a},要求支持m次操作: 单点修改 1 pos val 询 ...

  3. ACM-ICPC 2019南昌网络赛F题 Megumi With String

    ACM-ICPC 南昌网络赛F题 Megumi With String 题目描述 给一个长度为\(l\)的字符串\(S\),和关于\(x\)的\(k\)次多项式\(G[x]\).当一个字符串\(str ...

  4. 2019南昌网络赛H The Nth Item(二阶线性数列递推 + 广义斐波那契循环节 + 分段打表)题解

    题意: 传送门 已知\(F(n)=3F(n-1)+2F(n-2) \mod 998244353,F(0)=0,F(1)=1\),给出初始的\(n_1\)和询问次数\(q\),设每一次的答案\(a_i= ...

  5. 2019南昌网络赛G. tsy's number

    题意:\(\sum_{i=1}^n\sum_{j=1}^n\sum_{k=1}^n\frac{\phi(i)*\phi(j^2)*\phi(k^3)}{\phi(i)*\phi(j)*\phi(k)} ...

  6. 2018-2019 ACM-ICPC 徐州区域赛 部分题解

    题目链接:2018-2019 ACM-ICPC, Asia Xuzhou Regional Contest A. Rikka with Minimum Spanning Trees 题意: 给出一个随 ...

  7. 2019南昌网络赛  I. Yukino With Subinterval 树状数组套线段树

    I. Yukino With Subinterval 题目链接: Problem Descripe Yukino has an array \(a_1, a_2 \cdots a_n\). As a ...

  8. 2019南昌网络赛 hello 2019

    这道题和一道2017,2016的类似. A string t is called nice if a string “2017” occurs in t as a subsequence but a ...

  9. 2019南昌网络赛-I(单调栈+线段树)

    题目链接:https://nanti.jisuanke.com/t/38228 题意:定义一段区间的值为该区间的和×该区间的最小值,求给定数组的最大的区间值. 思路:比赛时还不会线段树,和队友在这题上 ...

  10. 2019南昌网络赛-M(二分)

    题目链接:https://nanti.jisuanke.com/t/38232 题意:给定字符串s(长度<=1e5),然后N组样例(N<=1e5),每组输入一个字符串t判断t是否为s的字串 ...

随机推荐

  1. dotnet 读 WPF 源代码笔记 渲染层是如何将字符 GlyphRun 画出来的

    从业务代码构建出来 GlyphRun 对象,在 WPF 的渲染层里,如何利用 GlyphRun 提供的数据将字符在界面呈现出来.本文将和大家聊聊从 WPF 的渲染层获取到 GlyphRun 数据,到调 ...

  2. Uncaught TypeError: (intermediate value)(intermediate value)(intermediate value)(intermediate value)...is not a function

    之前写完前端部分的时候总是会出现这个错误 对应代码 解决方法,在后面加上分号即可解决

  3. 01、Windows 排查

    Windows 分析排查 分析排查是指对 Windows 系统中的文件.进程.系统信息.日志记录等进行检测,挖掘 Windows 系统中是否具有异常情况 1.开机启动项检查 一般情况下,各种木马.病毒 ...

  4. 一种光电容积波PPG 转换到心电图ECG进行房颤检测的神经网络模型

    具体的软硬件实现点击 http://mcu-ai.com/ MCU-AI技术网页_MCU-AI人工智能 光电体积描记法(PPG)是一种经济有效的非侵入性技术,利用光学方法测量心脏生理学. PPG 在健 ...

  5. 解决VMware Workstation 与 Device/Credential Guard不兼容

    参考文档 https://blog.csdn.net/lizhengze1117/article/details/106566060

  6. linux文件查找工具详解

    linux文件查找详解 目录 linux文件查找详解 1.linux文件查找工具 1.1 find命令详解 1.1.1 根据文件名查找 1.1.2 根据属主属组查找 1.1.3 根据文件类型查找 1. ...

  7. SpringBoot模拟插入1000000万条数据

    一.数据库表准备 CREATE TABLE `student` ( `id` bigint NOT NULL COMMENT '用户id', `name` varchar(50) COLLATE ut ...

  8. JavaScript 实现前端文件下载

    A.download HTML5的A标签有一个download属性,可以告诉浏览器下载而非预览文件,很实用,参考链接:http://www.zhangxinxu.com/wordpress/2016/ ...

  9. gpu机器没有开启ipv6

    参考: https://blog.csdn.net/asdfaa/article/details/137884414 检查系统是否支持 IPv6,查看被禁用了 在启用 IPv6 之前,首先要确保您的系 ...

  10. .net core的学习小结

    课程:[.NET 6教程,.Net Core 2022视频教程,杨中科主讲] https://www.bilibili.com/video/BV1pK41137He/?p=159&share_ ...