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 second
using 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 second
using 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);
}