国庆清北刷题冲刺班 Day5 上午
来源:互联网 发布:nginx 查看模块 编辑:程序博客网 时间:2024/04/23 16:29
Day4 下午的跳了 哈哈哈哈
行列式
文件名:det.cpp(pas)
时间限制:1s
空间限制:512MB
题目描述:
有一个 N ×N 的矩阵 X,且矩阵内元素 X i,j 均为整数,现给出该矩阵第一行的元素,即
X 1,k ,k ∈ [1,N]。
试判断该矩阵的行列式是否有可能为 D。
输入格式:
第一行一个正整数 T,表示本题有 T 组数据。
每组数据第一行为一个正整数 N 和一个整数 D。接下来一行 N 个整数顺序给出 X 1,k 。
输出格式:
对于每组数据,输出一行。Y 表示存在矩阵 X 满足行列式为 D,N 表示不存在。
样例读入:
2
2 7
1 0
3 1
2 2 3
样例输出:
Y
Y
样例解释:
给出样例的一种解释方案:
det
(
1 0
0 7
)
= 7 det
2 2 3
0 −1 0
1 1 1
= 1
数据范围:
对于 30% 的数据,保证 T ⩽ 10,N ⩽ 10,|X 1,k | ⩽ 10,|D| ⩽ 10
对于 60% 的数据,保证 T ⩽ 100,N ⩽ 100,|X 1,k | ⩽ 1000,|D| ⩽ 1000
对于 100% 的数据,保证 T ⩽ 1000,N ⩽ 1000,|X 1,k | ⩽ 10 9 ,|D| ⩽ 10 9
T1 全场跳题,恩,就这样
序列
文件名:seq.cpp(pas)
时间限制:1s
空间限制:512MB
题目描述:
定义一个对序列操作 F:
F(list) =
F(odd) + F(even), If |list| > 1
list, If |list| = 1
,
即,每次将序列按奇偶下标分成两半,然后在回溯的时候拼接起来,例如:F({1,2,3,4}) =
{1,3,2,4},F({1,2,3,4,5,6,7}) = {1,5,3,7,2,6,4}。
记 {a n } 为 1 到 N 的升序排列,{b n } = F({a n })。
有 M 组询问,每次询问 {b n } 中,下标在 l 到 r 内,大小在 x 到 y 内的值之和 Ans。
由于数据可能很大,请将 Ans 对 mod 取模后输出。
输入格式:
第一行三个正整数,依次为 N,M,mod。
接下来 M 行,每行 4 个正整数,依次为 l,r,x,y。
输出格式:
M 行,对应 M 个询问,依次输出 Ans。
样例读入:
4 3 1000
2 4 1 3
1 3 3 4
1 1 100 200
样例输出:
5
3
0
样例解释:
{b n } = {1,3,2,4},所以 b 2 ,b 3 ,b 4 中在 [1,3] 内的项为 b 2 ,b 3 ,和为 5。
其他类似分析。
数据范围:
对于 30% 的数据,保证 N ⩽ 100,M ⩽ 100
对于 60% 的数据,保证 N ⩽ 10 5 ,M ⩽ 10 4
对于 100% 的数据,保证 N ⩽ 10 18 ,M ⩽ 5 × 10 4 ,1 ⩽ l ⩽ r ⩽ N,1 ⩽ x ⩽ y ⩽ 10 18 ,1 <
mod ⩽ 10
可持久化线段树可以通过 60% 的数据,但这并没有用到 {a n } 是 1 到 N 的升序排列的
性质。
考虑类似线段树的求解方法,记 getans(n,l,r,x,y) 表示当前在 F 中,是 1 到 n 的升序
排列,需要求得最终排好序后 l 到 r 范围内,大小在 x 到 y 之间的数值之和以及数字个数
(getans 返回一个 pair) ,思考如何分治。
注意到左右分裂的规律,可以算出此时序列需要向左边和右边分出多少,同时可以知道
l,r,x,y 四个数在子区间的大小,分治下去求解。在回溯时,将左右子树答案合并即可。
注意如果实现过程中会有类平方运算,可能会超 Long Long 范围,需要特别注意处理。
具体实现详见代码,复杂度为 O(M logN)。
考场60分代码:
#include<iostream>#include<cstring>#include<cstdio>#include<algorithm>#include<cmath> #include<cstdlib>using namespace std;inline void read(int &x){ x=0; int f=1; char c=getchar(); while(c>'9'||c<'0'){ if(c=='-')f=-1; c=getchar(); } while(c>='0'&&c<='9'){ x=x*10+c-'0'; c=getchar(); }}int n,m,Mod,a[105],b[10000005],c[105],cnt,d[105];void Build(int l,int r,int dep,int lx,int rx){ if(l==r) { b[++cnt]=rx;return; } int Mid=l+r>>1; if((r-l+1)%2==1){ Build(l,Mid,dep+1,lx,rx); Build(Mid+1,r,dep+1,lx+pow(2,dep),rx-pow(2,dep)); } else { Build(l,Mid,dep+1,lx,rx-pow(2,dep)); Build(Mid+1,r,dep+1,lx+pow(2,dep),rx); }}void build(int l,int r,int dep,int lx,int rx){ if(l==r) { b[++cnt]=rx; return; } int Mid=(l+r)>>1; if((r-l+1)%2==1){ build(l,Mid,dep+1,lx,rx); build(Mid+1,r,dep+1,lx+pow(2,dep),rx-pow(2,dep)); } else { build(l,Mid,dep+1,lx,rx-pow(2,dep)); build(Mid+1,r,dep+1,lx+pow(2,dep),rx); }}int main(int argc,char *argv[]){ freopen("seq.in","r",stdin); freopen("seq.out","w",stdout); read(n),read(m),read(Mod); Build(1,(n+1)>>1,1,1,n-((n+1)%2)); build((n+1>>1)+1,n,1,2,n-(n%2)); long long Ans=0; for(int l,r,x,y;m;m--){ Ans=0; read(l),read(r),read(x),read(y); if(x>y) swap(x,y); if(l>r) swap(l,r); if(x>n){ printf("0\n"); continue; } for(int j=l;j<=r;++j){ if(b[j]>=x&&b[j]<=y)Ans+=b[j]; if(Ans>=Mod) Ans-=Mod; } printf("%I64d\n",Ans); } fclose(stdin);fclose(stdout); return 0;}
本来我以为的这个做法只能拿到30分,就开了30% 的数组大小,开大数组之后,发现同样的做法可以拿到60分,gg
AC代码:
#include<iostream>#include<cstring>#include<cstdio>#define st first #define nd secondusing namespace std;typedef long long LL;typedef pair<LL,LL> pa;LL n,m,Mod,l,r,u,v;inline void read(int &x){ x=0; int f=1; char c=getchar(); while(c>'9'||c<'0'){ if(c=='-')f=-1; c=getchar(); } while(c>='0'&&c<='9'){ x=x*10+c-'0'; c=getchar(); } x*=f;}pa solve(LL rr, LL l, LL r, LL x, LL y){ if(x > rr || l > r) return make_pair(0, 0); if(l == 1 && r == rr){ x = max(x, 1LL),y = min(y, rr); LL s; if((x + y) % 2 == 0) s = ( (x + y) / 2 % Mod) * ( (y - x + 1)%Mod ) % Mod; else s = ( (x + y) % Mod ) * ((y - x + 1) / 2 % Mod) % Mod; return make_pair(s % Mod, y - x + 1); } LL Mid = rr + 1 >>1; if(r <= Mid){ pa ret = solve(Mid, l, r, x / 2 + 1, (y + 1) / 2); return make_pair((ret.st * 2 - ret.nd) % Mod,ret.nd); } else if(l > Mid){ pa ret = solve(rr - Mid, l - Mid, r - Mid, (x + 1) / 2, y / 2); return make_pair(ret.st * 2 % Mod, ret.nd); } else { pa ret1 = solve(Mid,l,Mid,x / 2 + 1,(y + 1) / 2); pa ret2 = solve(rr - Mid,1,r - Mid,(x + 1) / 2,y / 2); return make_pair( (ret1.st * 2 - ret1.nd + ret2.st * 2) % Mod, (ret1.nd + ret2.nd) % Mod); }}int main(int argc,char *argv[]){ freopen("seq.in","r",stdin); freopen("seq.out","w",stdout); scanf("%I64d%I64d%I64d",&n,&m,&Mod); for(int i=0; i<m; ++i){ scanf("%I64d%I64d%I64d%I64d", &l, &r, &u, &v); pa Ans = solve(n, l, r, u, v); printf("%I64d\n", (Ans.st + Mod) % Mod ); } fclose(stdin); fclose(stdout); return 0;}
数数
文件名:bitcount.cpp(pas)
时间限制:1s
空间限制:512MB
题目描述:
给出一棵 N 个节点,以 1 为根的有根树。
定义树上两个节点 x 和 y 的距离函数 d:
d(x,y) = Dist(x,z) + Dist(y,z),
其中 z 为 x 和 y 的最近公共祖先,Dist(a,b) 为 a 到 b 路径上边数 m 的二进制下 1 的个数。
希望你能求出树上每对节点的 d 值之和,即:
Ans =
n
∑
i=1
n
∑
j=i+1
d(i,j).
输入格式:
第一行一个正整数 N。
接下来 N − 1 行,每行两个正整数 A i ,B i ,表示一条树边连接 A i 和 B i 。
输出格式:
一行,一个整数 Ans。
样例读入:
4
1 2
1 3
2 4
样例输出:
8
样例解释:
#include <iostream>#include <cstdio>#include <cstdlib>#include <cstring>#include <string>#include <cmath>#include <vector>#define st first#define nd secondusing namespace std;struct edge { int x,nxt; };typedef long long LL;const int N = 1e5 + 10;struct edge e[2 * N];int fa[N][17], hd[N], fom[N], siz[N], nxt[N], cnt[N][17], f[N][17];int n, m, x, y, l;LL ans;void link(int x, int y) { e[++l].x = y; e[l].nxt = hd[x]; hd[x] = l;}void DFS_LCA(int x) { fa[x][0] = fom[x]; siz[x] = 1; for (int i = 1; i <= 16; ++i) fa[x][i] = fa[fa[x][i - 1]][i - 1]; for (int p = hd[x]; p; p = e[p].nxt) if (e[p].x != fom[x]) { fom[e[p].x] = x; DFS_LCA(e[p].x); siz[x] += siz[e[p].x]; }}void DFS_Ans(int x) { for (int p = hd[x]; p; p = e[p].nxt) if (e[p].x != fom[x]) nxt[x] = e[p].x, DFS_Ans(e[p].x); for (int i = 0; i <= 16; ++i) { ans += siz[fa[x][i]] - siz[nxt[fa[x][i]]]; cnt[fa[x][i]][i]++; f[fa[x][i]][i]++; } for (int i = 1; i <= 16; ++i) for (int j = 0; j <= i - 1; ++j) { ans += LL(cnt[x][i] + f[x][i]) * LL(siz[fa[x][j]] - siz[nxt[fa[x][j]]]); cnt[fa[x][j]][j] += cnt[x][i]; f[fa[x][j]][j] += f[x][i] + cnt[x][i]; }}int main() { freopen("bitcount.in", "r", stdin); freopen("bitcount.out", "w", stdout); scanf("%d", &n); for (int i = 1; i < n; ++i) { scanf("%d%d", &x, &y); link(x, y); link(y, x); } DFS_LCA(1); siz[0] = siz[1]; nxt[0] = 1; DFS_Ans(1); printf("%I64d\n", ans); fclose(stdin); fclose(stdout);}
- 国庆清北刷题冲刺班 Day5 上午
- 国庆清北刷题冲刺班 Day5 下午
- 国庆清北刷题冲刺班 Day1 上午
- 国庆清北刷题冲刺班 Day2 上午
- 国庆清北刷题冲刺班 Day3 上午
- 国庆清北刷题冲刺班 Day4 上午
- 国庆清北刷题冲刺班 Day6 上午
- 国庆清北刷题冲刺班 Day7 上午
- 国庆清北刷题冲刺班 Day1 下午
- 国庆清北刷题冲刺班 Day2 下午
- 国庆清北刷题冲刺班 Day3 下午
- 国庆清北刷题冲刺班 Day6 下午
- 国庆清北刷题冲刺班 Day7 下午
- day5上午总结
- qbxt国庆水题记day5
- 济南刷题冲刺 Day1 上午
- 济南刷题冲刺 Day2 上午
- 【泉州一中国庆集训day5】label
- IOS学习笔记——iOS组件之UIScrollView详解(各个方法)
- JVM调优总结(5):典型配置
- 关于Ubuntu中Could not get lock /var/lib/dpkg/lock解决方案
- PTA 7-6(队列) 银行排队问题之单队列多窗口加VIP服务(30 分) 30分代码
- JVM调优总结(6):新一代的垃圾回收算法
- 国庆清北刷题冲刺班 Day5 上午
- 不带头节点的单链表及其基本操作(Java实现)
- Gauge中文文档(10)—故障处理
- IIS与IIC
- imageLoader框架
- Java基础集合类(二):LinkedList详解
- 不爱说话?社交无能?或许你可以试试这种说话术
- 2017下半年ACM-ICPC网络赛签到题汇总
- 带头节点的双链表及其基本操作(Java实现)