//10月1去了清北,又没上成洛谷
//作为洛谷的忠实粉真不应该
//今天做了做
#T1#
(想了解这个直接搜题目名即可)
题目描述
我妻蛤乃给你出了一道送命题:
黄梅时节家家雨,青草池塘处处蛙~
有n只青蛙,第i只青蛙会每过xi秒会连续叫yi秒。然而由于青蛙的寿命在增加,所以从第二次开始每次休息结束
后这只青蛙连续叫的时间会增加zi秒。
给定n只青蛙,每一只的xi,yi,zi,以及时间t,求在前t秒中,所有青蛙共叫了多少秒。
输入输出格式
输入格式:
第一行两个数n和t
之后n行,第i+1行每行三个非负整数xi,yi,zi
输出格式:
一行一个数表示答案
输入输出样例
输入样例#1
【子任务】
子任务会给出部分测试数据的特点。 如果你在解决题目中遇到了困难, 可以尝试只解决一部分测试数据。
8 10
9 1 1
1 9 9
4 1 0
2 3 3
1 0 0
1 4 0
9 2 5
1 2 1
输出样例#1:
34
输入样例#2:
1 233333
233 233 233
输出样例#2:
223081
输入样例#3:
10 100000000
1 0 0
1 0 5
1 2 2
1 2 8
1 3 0
1 5 0
1 5 2
1 5 5
1 7 0
1 8 3
输出样例#3:
845787522
每个测试点的数据规模及特点如下表:
测试点编号 n的范围 t的范围 特殊性质
测试点1 n = 1
测试点2 n = 100 t <= 100 x = 0
测试点3 n = 100 y = 0
测试点4 n = 100 z = 0
测试点5 n = 100
测试点6 n = 100000 t <= 100 x = y = z
测试点7 n = 100000 t <= 100 z = 0
测试点8 n = 100000 y = 0
测试点9 n = 100000 t <= 100000
测试点10 n = 100000
对于100%的数据,n <= 100000 , t <= 2000000000,x + y + z > 0
0 <= x , y , z <= 2000000000
【说明】
【样例1说明】
每只青蛙分别叫了1,9,2,6,0,8,1,7秒
【样例2说明】
那只青蛙叫了223081秒
【样例3说明】
每只青蛙分别叫了
0,99993675,99990000,99994999,75000000,83333333,99990002,99993676,87500000,99991837秒
其实看到这道题就能想到用前n项和求
后来想了想爆搜会超时,可以用二分来优化下
注意二分时求前n项和时的边界,可以用 t/(X+Y+Z)来当,要是太大可能会爆long long(我第一次70分就是爆了long long)
#include
#include
#include
#include
using namespace std;
long long n,t;
long long read() {
long long x = 0, f = 1;
char ch = getchar();
while(ch < '0' || ch > '9') {
if(ch == '-') f = -1;
ch = getchar();
}
while(ch >= '0' && ch <= '9') {
x = (x << 1) + (x << 3) + ch - '0';
ch = getchar();
}
return x * f;
}
long long x,y,z,sum = 0;
bool pd(long long mid) {
return (x + y) * mid + ( mid * (mid - 1) ) / 2 * z <= t;
}
void work() {
x = read(), y = read(), z = read();
long long l = 0, r = t / (x + y + z),ans = 0;
while(l <= r) {
long long mid = (l + r) >> 1;
if(pd(mid)) {
ans = mid;
l = mid + 1;
}
else r = mid - 1;
}
long long p = y * ans + ( ans * (ans - 1) ) / 2 * z;
sum += p;
p = t - p - x * ans - x;
if(p > 0) sum += p;
}
int main() {
n = read(), t = read();
for(int i = 1; i <= n; i++) {
work();
}
cout<
#T2#
题目描述
数据结构大师ddd给你出了一道题:
给你一棵树,最开始点权为0,每次将与一个点x树上距离<=1的所有点点权+1,之后询问这些点修改后的点权
和
输入输出格式
输入输出格式
输入格式:
第一行两个数n和m
之后一行n-1个数,第i个数fa[i + 1]表示i + 1点的父亲编号,保证fa[i + 1] < i + 1
之后一行m个数,每个数x依次表示这次操作的点是x
输出格式:
输出一个数,即这m次询问的答案的和
保证答案在有符号64位整数范围内
输入输出样例
说明
样例#3,#4,#5,#6见下发的文件
【子任务】
子任务会给出部分测试数据的特点。
如果你在解决题目中遇到了困难, 可以尝试只解决一部分测试数据。
每个测试点的数据规模及特点如下表:
测试点编号 n的范围 m的范围 特殊性质
测试点1 n = 1000 m = 1000 数据随机
测试点2 n = 1000 m = 1000 数据随机
测试点3 n = 100000 m = 100000
输入样例#1:
6 3
1 1 2 3 3
1 2 3
输出样例#1:
15
输入样例#2:
6 10
1 1 2 3 3
1 4 6 5 2 3 3 3 3 3
输出样例#2:
115
第4页 共7页
测试点编号 n的范围 m的范围 特殊性质
测试点4 n = 100000 m = 100000
测试点5 n = 100000 m = 1000000 树是一条链
测试点6 n = 100000 m = 1000000
测试点7 n = 100000 m = 1000000
测试点8 n = 100000 m = 3000000
测试点9 n = 100000 m = 3000000
测试点10 n = 100000 m = 10000000
//表示赛后看std的方法没看懂
//但我的方法也A了
记录每个点在最后处理完的状态
可以将那个点改变过记录下来,然后dfs一遍
注意题目 保证fa[i + 1] < i + 1 所以只用建单向边就好
然后对于每个点对答案的贡献就是f[i] * (f[i] + 1) / 2
#include
#include
#include
#include
using namespace std;
const int maxn = 100000 + 100;
int n,m;
struct edge {
int u,v;
int next;
}e[maxn << 1];
int head[maxn], tot = 0;
int read() {
int x = 0, f = 1;
char ch = getchar();
while(ch < '0' || ch > '9') {
if(ch == '-') f = -1;
ch = getchar();
}
while(ch >= '0' && ch <= '9') {
x = (x << 1) + (x << 3) + ch - '0';
ch = getchar();
}
return x * f;
}
void add(int u, int v) {
e[++tot] = (edge){u,v,head[u]};
head[u] = tot;
}
int val[maxn],f[maxn];
void dfs(int x, int fa) {
f[x] += val[x] + val[fa];
for(int i = head[x]; i; i = e[i].next) {
int v = e[i].v;
f[x] += val[v];
dfs(v,x);
}
}
int main() {
n = read(), m = read();
for(int i = 2; i <= n; i++) {
int v = read();
add(v,i);
}
for(int i = 1; i <= m; i++) {
int a = read();
val[a]++;
}
dfs(1,0);
long long sum = 0;
for(int i = 1; i <= n; i++) {
sum += (long long)f[i] * (f[i] + 1) / 2;
}
cout<
#T3#
题目描述
江爷爷给你出了一道题:
给你一个图,保证每个点最多属于一个简单环,每个点度数最多为3,求这个图有多少“眼镜图形个数”
保证图联通哦~
其中“眼镜图形个数”,定义为三元组(x,y,S),其中x和y表示图上的两个点,S表示一条x到y的简单路径,而且必
须满足:
1.x和y分别在两个不同的简单环上
2.x所在的简单环与路径S的所有交点仅有x,y所在的简单环与路径S的所有交点仅有y。
(x,y,S)与(y,x,S)算同一个眼镜
如果你无法理解,可以参考样例。
保证图是联通的
输入输出格式
输入格式:
第一行两个数n和m
之后m行,每行两个数x,y表示x和y之间有一条边。
输出格式:
输出一个数,表示眼镜的个数对19260817取膜的结果
输入输出样例
输入样例#1:
说明
样例#3,#4,#5,#6见下发的文件
非常抱歉,出了点小锅,sample5.out好像是空文件,应该是6734568
【子任务】
11 12
1 2
2 3
3 4
4 5
5 1
4 6
6 7
7 8
8 9
9 10
10 11
11 7
输出样例#1:
1
输入样例#2:
14 16
1 2
2 3
3 4
4 1
3 5
5 6
6 7
7 8
8 9
9 6
9 13
13 14
13 10
10 11
11 12
12 10
输出样例#2:
4
子任务会给出部分测试数据的特点。
如果你在解决题目中遇到了困难, 可以尝试只解决一部分测试数据。
测试点编号 n的范围 m的范围 特殊性质
测试点1 n <= 10 m <= 20
测试点2 n <= 20 m <= 40
测试点3 n <= 20 m <= 40
测试点4 n <= 2000 m <= 4000
测试点5 n <= 2000 m <= 4000
测试点6 n <= 1000000 m <= 2000000 简单环个数 <= 2000
测试点7 n <= 1000000 m <= 2000000 简单环个数 <= 2000
测试点8 n <= 1000000 m <= 2000000
测试点9 n <= 1000000 m <= 2000000
测试点10 n <= 1000000 m <= 2000000
//十月1回来后某dalao就让我看这个题,说是树形DP让我推推
首先缩点,注意是无向图不能直接套tarjan
然后就是恶心的树形DP
用f[x]表示以x为根的子树,到x构成的“一半的眼镜”的数量
注意根节点是不是环,如果是环要特殊处理
#include
#include
#include
#include
using namespace std;
#define ll long long
const int maxn = 1000000 + 100;
const int mod = 19260817;
int n,m;
int x[maxn << 1],y[maxn << 1];
vectorq[maxn];
int read() {
int x = 0, f = 1;
char ch = getchar();
while(ch < '0' || ch > '9') {
if(ch == '-') f = -1;
ch = getchar();
}
while(ch >= '0' && ch <= '9') {
x = (x << 1) + (x << 3) + ch - '0';
ch = getchar();
}
return x * f;
}
//缩点
int vis[maxn],f[maxn],belong[maxn],col[maxn],cnt = 0;
void dfs(int x) {
vis[x] = 1;
for(int i = 0; i < q[x].size(); i++) {
int v = q[x][i];
if(v == f[x]) continue;
if(!vis[v]) f[v] = x, dfs(v);
else if(!belong[v]) {
int t = x;
col[++cnt] = 1;
while(1) {
belong[t] = cnt;
if(t == v) break;
t = f[t];
}
}
}
}
struct edge {
int u,v,next;
}e[maxn << 1];
int head[maxn],tot = 0;
void add(int u, int v) {
e[++tot] = (edge){u,v,head[u]};
head[u] = tot;
}
int fa[maxn],dp[maxn];
ll ans = 0;
void DP(int x) {
for(int i = head[x]; i ; i = e[i].next) {
int v = e[i].v;
if(v != fa[x]) {
fa[v] = x;
DP(v);
ans = (ans + (ll)dp[v] * dp[x] * (col[x] ? 2 : 1) % mod) % mod;
dp[x] = (dp[x] + dp[v]) % mod;
}
}
if(col[x]) {
ans = (ans + dp[x]) % mod;
dp[x] = (dp[x] * 2 + 1) % mod;
}
}
int main() {
n = read(), m = read();
for(int i = 1; i <= m; i++) {
x[i] = read(), y[i] = read();
q[x[i]].push_back(y[i]);
q[y[i]].push_back(x[i]);
}
dfs(1);
for(int i = 1; i <= n; i++) if(!belong[i]) belong[i] = ++cnt;
for(int i = 1; i <= m; i++) {
if(belong[x[i]] != belong[y[i]]) {
add(belong[x[i]],belong[y[i]]),add(belong[y[i]],belong[x[i]]);
}
}
DP(1);
cout<