hinhin可否不要老,令创新高
- A 日期统计
- B 01 串的熵
- C 冶炼金属
- D: 飞机降落
- E: 接龙数列
- F: 岛屿个数
- G: 子串简写
- H: 整数删除
- I: 景区导游
- J: 砍树
A 日期统计
#include <bits/stdc++.h>
using namespace std;
#define int long long int
#define pii pair<int,int>
const int N=105;
const int M=2e4+5;
int n;
int a[N];
int res=0;
int mon[15]={0,31,28,31,30,31,30,31,31,30,31,30,31};
bool judge(int x){
int y=x/10000;
int m=(x%10000)/100;
int d=x%100;
if(y!=2023||m<1||m>12||d<1||d>mon[m])return false;
else return true;
// if(y==2023&&m>=1&&m<=12&&d>=1&&d<=mon[m])return true;
// else return false;
}
map<int,int> mp;
void dfs(int u,int len,int sum){
// cout<<sum<<"hhh"<<endl;
if(len==8){
if(!mp[sum]){
if(judge(sum))res++;
mp[sum]=1;
}
return ;
}
if(u>=100)return ;
if(len==4&&sum!=2023)return ;
dfs(u+1,len+1,sum*10+a[u]);
dfs(u+1,len,sum);
}//6:03 21:33
signed main(){
for(int i=0;i<100;i++){
cin>>a[i];
}
dfs(0,0,0);
cout<<res;
return 0;
}
#include <bits/stdc++.h>
using namespace std;
#define int long long int
#define pii pair<int,int>
const int N=105;
const int M=2e4+5;
int n;
int a[N];
int res=0;
int mon[15]={0,31,28,31,30,31,30,31,31,30,31,30,31};
bool judge(int x){
int y=x/10000;
int m=(x%10000)/100;
int d=x%100;
if(y!=2023||m<1||m>12||d<1||d>mon[m])return false;
else return true;
// if(y==2023&&m>=1&&m<=12&&d>=1&&d<=mon[m])return true;
// else return false;
}
map<int,int> mp;
void dfs(int u,int s,int sum){
// cout<<"hhh"<<endl;
if(u==8){
if(!mp[sum]){
if(judge(sum))res++;
mp[sum]=1;
}
return ;
}
if(u==4&&sum!=2023)return ;40
for(int i=s;i<100;i++){
dfs(u+1,i+1,sum*10+a[i]);
}
}
signed main(){
for(int i=0;i<100;i++){
cin>>a[i];
}
dfs(0,0,0);
cout<<res;
return 0;
}
B 01 串的熵
#include <bits/stdc++.h>
#define int long long int
using namespace std;
signed main(){
int n=23333333;
for(int i=0;i<=n/2;i++){
int j=n-i;
// cout<<"h";
double x=-1.0*(i*i)/n*log2(1.0*i/n)-1.0*(j*j)/n*log2(1.0*j/n);
if(abs(x-11625907.5798)<=0.0001){
cout<<i<<endl;
// break;
}
}
return 0;
}
写的时候没跑出来,仅仅是因为给(i*i)
加了括号,爆了int!!!
双精度浮点的表示范围:-1.79E+308 ~ +1.79E+308
基本类型:int 二进制位数:32(4字节)
最小值:Integer.MIN_VALUE= -2147483648 (-2的31次方)
最大值:Integer.MAX_VALUE= 2147483647 (2的31次方-1
double范围很大,基本不可能爆,不放心用long double
C语言int/double数据类型的范围
#include <stdio.h>
#include <limits.h>
# include <float.h>
int main()
{
printf("int类型数据所占空间=%d\n", sizeof(int));
// int类型数据范围
// 方法1
printf("int最小值=%d, int最大值=%d\n", INT_MIN, INT_MAX); // 使用limits.h里的宏
//方法2
signed int max = (1 << (sizeof(int) * 8 - 1)) - 1; // 自己计算
signed int min = -(1 << (sizeof(int) * 8 - 1));
printf("int最小值=%d, int最大值=%d\n", min, max);
// 方法3
printf("int最小值=%d, int最大值=%d\n", max+1, min-1);
// double数据类型精度及范围--数据很大
printf("float类型数据所占空间:%d\n", sizeof(float));
printf("double类型数据所占空间:%d\n", sizeof(double));
printf("double精度:%lf\n"); //有警告,不过可以运行
printf("double最小值=%lf\n, double最大值=%lf\n", -DBL_MAX, DBL_MAX); //使用float.h的宏
return 0;
}
C 冶炼金属
#include <bits/stdc++.h>
using namespace std;
#define int long long int
#define pii pair<int,int>
//const int N=105;
const int N=1e4+5;
int n;
//struct node{
// int x,y;
//}a[N];
int res=0;
int x,y;
signed main(){
scanf("%d",&n);
int minx=0x3f3f3f3f;
int maxx=0;
for(int i=0;i<n;i++){
scanf("%d %d",&x,&y);
minx=min(minx,x/y);
maxx=max(maxx,x/(y+1));
}
cout<<maxx+1<<" "<<minx;
return 0;
}
D: 飞机降落
2
3
0 100 10
10 10 10
0 2 20
3
0 10 20
10 10 20
20 10 20
暴力枚举序列
先看给定范围,范围小直接暴力,不要想任何关于逻辑关于贪心
#include <bits/stdc++.h>
//#define int long long int
#define pii pair<int,int>
using namespace std;
const int N=15;
int T,m,n;
struct node{
int t,d,l,late;//到达,盘旋,降落过程
}v[N];
int s[N];
int vis[N];
int fg=0;
void dfs(int u){
if(u==n+1){
// for(int i=1;i<=n;i++)cout<<s[i]<<" ";
// cout<<endl;
int t=v[s[1]].t;
int d=v[s[1]].d;
int l=v[s[1]].l;
int now=t+l;//前一架落地了,不怕来的晚,就怕来得早
for(int i=2;i<=n;i++){
if(now>v[s[i]].late)return ;
if(now<v[s[i]].t)now=v[s[i]].t;
now+=v[s[i]].l;
}
fg=1;
return ;
}
for(int i=1;i<=n;i++){
if(!vis[i]){
if(fg)return ;
s[u]=i,vis[i]=1,dfs(u+1),vis[i]=0;
}
}
}
signed main(){//54
scanf("%d",&T);
while(T--){
fg=0;
memset(vis,0,sizeof(vis));
scanf("%d",&n);
for(int i=1;i<=n;i++){
scanf("%d %d %d",&v[i].t,&v[i].d,&v[i].l);
v[i].late=v[i].t+v[i].d;//最晚这个点一定要开始降
}
dfs(1);
if(fg)cout<<"YES"<<endl;
else cout<<"NO"<<endl;
}
return 0;
}
//2
//3
//0 100 10
//10 10 10
//0 2 20
//3
//0 10 20
//10 10 20
//20 10 20
E: 接龙数列
先来个暴力
中了这段代码的毒了
for(int i=start;i+sum<=m;i++){
// int tmp=rd+(1<<i);
dfs(u+1,sum+i,i);
}
最本质的暴力搜索是,已知一个具体的序列,选出一个子序列(注意了隐含的条件是选取元素的顺序和原序列顺序一致),满足某种条件,爆搜的方式是对于1~n每个元素,走取或者不取两个分支
这道题的暴力就是最原本的形式,u是指向原数组的指针,通过偏移将路径像远处延伸
从1~n依次考虑某个元素取或者不取自然可以保证顺序
至于1~n打乱顺序,u是指向目标数组的指针,代表这个位置该放哪个元素,通过数组长度的增长将路径像远处延伸,分支的可能是各个元素,需要遍历原数组
至于上面这段,
怎么说呢,就是具体知道原来的顺序,不需要通过start控制选取元素的顺序,start是控制大小的,
#include <bits/stdc++.h>
using namespace std;
#define int long long int
#define pii pair<int,int>
const int N=1e5+5;
int n;
int res=0;
int head(int u){
int x=0;
while(u){
x=u%10;
u/=10;
}
return x;
}
int tail(int u){
return u%10;
}
int a[N];
void dfs(int u,int len,int t){
// cout<<len<<endl;
if(u==n+1){
res=max(res,len);
return ;
}
if(t==-1||t==head(a[u]))dfs(u+1,len+1,tail(a[u]));
dfs(u+1,len,t);
}
signed main(){
scanf("%d",&n);
for(int i=1;i<=n;i++){
scanf("%d",&a[i]);
}
dfs(1,0,-1);
cout<<n-res;
return 0;
}
开始dp
I idiot
for(int i=1;i<=n;i++){
if(t==-1||t==head(a[i]))
dp[i]=dp[i-1]+1,t=tail(a[i]);
else dp[i]=dp[i-1];//首先这个最基本的递推式逻辑就不对
//按这样的话,dp[i]的含义不是以a[i]结尾的最长接龙序列长度(但是求法是这样),
//而是前i个里出现的最长子序列的长度,那么这个最长子序列就不一定以a[i]结尾
//如果dp[i]代表前i个里出现的最长子序列的长度,那么dp[i]可能由若干状态递推而来
//所以还是稳妥的,让dp[i]代表以a[i]结尾的最长接龙序列长度
//那么res=max(res,dp[i])
}
#include <bits/stdc++.h>
using namespace std;
#define int long long int
#define pii pair<int,int>
const int N=1e5+5;
int n;
int res=0;
int head(int u){
int x=0;
while(u){
x=u%10;
u/=10;
}
return x;
}
int tail(int u){
return u%10;
}
int a[N];
int dp[N];//以a[i]结尾的最长合格长度
int num[N];//以数字num[i](1~9)结尾的最长合格长度
signed main(){
scanf("%d",&n);
for(int i=1;i<=n;i++){
scanf("%d",&a[i]);
}
for(int i=1;i<=n;i++){
int h=head(a[i]);
int t=tail(a[i]);
dp[i]=num[h]+1;
//一定要以a[i]结尾,就要找到tail(a[?])==head[a[i]]
num[t]=max(dp[i],num[t]);
res=max(res,dp[i]);
}
cout<<n-res;
return 0;
}
int f;
for(int i=1;i<=n;i++){
int h=head(a[i]);
int t=tail(a[i]);
f=num[h]+1;
//一定要以a[i]结尾,就要找tail(a[?])==head[a[i]]
num[t]=max(f,num[t]);
res=max(res,f);
}
cout<<n-res;
for(int i=1;i<=n;i++){
int h=head(a[i]);
int t=tail(a[i]);
num[t]=max(num[h]+1,num[t]);
res=max(res,num[t]);
}
cout<<n-res;
F: 岛屿个数
2
5 5
01111
11001
10101
10001
11111
5 6
111111
100001
010101
100001
111111
#include <bits/stdc++.h>
//#define int long long int
#define pii pair<int,int>
using namespace std;
const int N=55;
int T,m,n;
string str[N];
int vis[N][N];
int dx[4]={0,0,1,-1};
int dy[4]={1,-1,0,0};
bool inside(int cx,int cy){
return cx>=0&&cx<m&&cy>=0&&cy<n;
}
int num;
void dfs(int x,int y){
for(int i=0;i<4;i++){
int cx=x+dx[i];
int cy=y+dy[i];
if(inside(cx,cy)&&str[cx][cy]-'0'==1&&!vis[cx][cy]){
vis[cx][cy]=num;
dfs(cx,cy);
}
}
}
map<int,bool> mp;//岛屿编号 是否冲出去
//void dfs1(int x,int y,int sg){
//
// for(int i=0;i<4;i++){
// int cx=x+dx[i];
// int cy=y+dy[i];
// if(inside(cx,cy)&&str[cx][cy]-'0'==1&&!vis[cx][cy]){
// vis[i][j]=num;
// dfs(cx,cy);
走到0也走,只要能走出去
// }
// }
//}
int viss[N][N];
queue<pii> Q;
int forbid;
bool bfs(int sg){
int x, y;
// cout<<sg<<endl<<endl;
while(!Q.empty()){
pii t=Q.front();Q.pop();
x=t.first,y=t.second;
if(x==0||x==m-1||y==0||y==n-1){
if(str[x][y]!=forbid){
// Q.clear();
return true;
}
}
// cout<<x<<" "<<y<<endl;
for(int i=0;i<4;i++){
int cx=x+dx[i];
int cy=y+dy[i];
if(inside(cx,cy)&&!viss[cx][cy]&&(vis[cx][cy]!=forbid)){
viss[cx][cy]=1;
// cout<<cx<<" "<<cy<<"dvwierl"<<endl;
Q.push({cx,cy});
// 走到0也走,只要能走出去
}
}
}
return false;
}
signed main(){
scanf("%d",&T);
while(T--){
memset(vis,0,sizeof(vis));
mp.clear();
scanf("%d %d",&m,&n);
for(int i=0;i<m;i++)cin>>str[i];
// dfs();
num=1;
for(int i=0;i<m;i++){
for(int j=0;j<n;j++){
if(str[i][j]-'0'==1&&!vis[i][j])vis[i][j]=num,dfs(i,j),num++;
}
}
// for(int i=0;i<m;i++){
// for(int j=0;j<n;j++){
// cout<<vis[i][j]<<" ";
// }
// cout<<endl;
// }
int cnt=0;
for(int i=0;i<m;i++){
for(int j=0;j<n;j++){
if(str[i][j]-'0'==1&&!mp[vis[i][j]]){
for(forbid=1;forbid<num;forbid++){
if(forbid==vis[i][j])continue;
// cout<<"hhh"<<endl;
mp[vis[i][j]]=1;
while(!Q.empty()){
Q.pop();
}
memset(viss,0,sizeof(viss));
Q.push({i,j});
viss[i][j]=1;
bool f=bfs(vis[i][j]);
// bool f=dfs1(i,j,vis[i][j]);
if(!f){
cnt++;break;//被包围了,不再看下去
}
}
}
}
}
cout<<num-1-cnt<<endl;
}
return 0;
}
//错在,子岛的定义是,不被一个道阻拦,而被多个岛屿阻拦不算自岛
//2
//5 5
//01111
//11001
//10101
//10001
//11111
//5 6
//111111
//100001
//010101
//100001
//111111
斜对角也可以逃出,但超时了
对于每一个岛屿,枚举别的所有岛屿,看看是否被别的岛屿包围,不能被任何岛屿包围
由于是八角包围,包围别人的母岛一定是一个岛,连起来的嘛
#include <bits/stdc++.h>
//#define int long long int
#define pii pair<int,int>
using namespace std;
const int N=55;
int T,m,n;
string str[N];
int vis[N][N];
int dx[8]={0,0,1,-1,1,1,-1,-1};
int dy[8]={1,-1,0,0,1,-1,1,-1};
bool inside(int cx,int cy){
return cx>=0&&cx<m&&cy>=0&&cy<n;
}
int num;
void dfs(int x,int y){
for(int i=0;i<4;i++){
int cx=x+dx[i];
int cy=y+dy[i];
if(inside(cx,cy)&&str[cx][cy]-'0'==1&&!vis[cx][cy]){
vis[cx][cy]=num;
dfs(cx,cy);
}
}
}
map<int,bool> mp;//岛屿编号 是否冲出去
//void dfs1(int x,int y,int sg){
//
// for(int i=0;i<4;i++){
// int cx=x+dx[i];
// int cy=y+dy[i];
// if(inside(cx,cy)&&str[cx][cy]-'0'==1&&!vis[cx][cy]){
// vis[i][j]=num;
// dfs(cx,cy);
走到0也走,只要能走出去
// }
// }
//}
int viss[N][N];
queue<pii> Q;
int forbid;
bool bfs(int sg){
int x, y;
// cout<<sg<<endl<<endl;
while(!Q.empty()){
pii t=Q.front();Q.pop();
x=t.first,y=t.second;
if(x==0||x==m-1||y==0||y==n-1){
if(str[x][y]!=forbid){
// Q.clear();
return true;
}
}
// cout<<x<<" "<<y<<endl;
for(int i=0;i<8;i++){
int cx=x+dx[i];
int cy=y+dy[i];
if(inside(cx,cy)&&!viss[cx][cy]&&(vis[cx][cy]!=forbid)){
viss[cx][cy]=1;
// cout<<cx<<" "<<cy<<"dvwierl"<<endl;
Q.push({cx,cy});
// 走到0也走,只要能走出去
}
}
}
return false;
}
signed main(){
scanf("%d",&T);
while(T--){
memset(vis,0,sizeof(vis));
mp.clear();
scanf("%d %d",&m,&n);
for(int i=0;i<m;i++)cin>>str[i];
// dfs();
num=1;
for(int i=0;i<m;i++){
for(int j=0;j<n;j++){
if(str[i][j]-'0'==1&&!vis[i][j])vis[i][j]=num,dfs(i,j),num++;
}
}
// for(int i=0;i<m;i++){
// for(int j=0;j<n;j++){
// cout<<vis[i][j]<<" ";
// }
// cout<<endl;
// }
int cnt=0;
for(int i=0;i<m;i++){
for(int j=0;j<n;j++){
if(str[i][j]-'0'==1&&!mp[vis[i][j]]){
for(forbid=1;forbid<num;forbid++){
if(forbid==vis[i][j])continue;
// cout<<"hhh"<<endl;
mp[vis[i][j]]=1;
while(!Q.empty()){
Q.pop();
}
memset(viss,0,sizeof(viss));
Q.push({i,j});
viss[i][j]=1;
bool f=bfs(vis[i][j]);
// bool f=dfs1(i,j,vis[i][j]);
if(!f){
cnt++;break;//被包围了,不再看下去
}
}
}
}
}
cout<<num-1-cnt<<endl;
}
return 0;
}
//错在,子岛的定义是,不被一个道阻拦,而被多个岛屿阻拦不算自岛
//2
//5 5
//01111
//11001
//10101
//10001
//11111
//5 6
//111111
//100001
//010101
//100001
//111111
AC 搞半天,原来,只要不被八个角都被包围就好,也不用那么强的要求,不要求八个角都是一个岛的
woc,突然发现,如果被包围了,那么一定是被同一个岛包围的TTTTTTTT我是傻子
#include <bits/stdc++.h>
//#define int long long int
#define pii pair<int,int>
using namespace std;
const int N=55;
int T,m,n;
string str[N];
int vis[N][N];
int dx[8]={0,0,1,-1,1,1,-1,-1};
int dy[8]={1,-1,0,0,1,-1,1,-1};
bool inside(int cx,int cy){
return cx>=0&&cx<m&&cy>=0&&cy<n;
}
int num;
void dfs(int x,int y){
for(int i=0;i<4;i++){
int cx=x+dx[i];
int cy=y+dy[i];
if(inside(cx,cy)&&str[cx][cy]-'0'==1&&!vis[cx][cy]){
vis[cx][cy]=num;
dfs(cx,cy);
}
}
}
map<int,bool> mp;//岛屿编号 是否冲出去
int viss[N][N];
queue<pii> Q;
bool bfs(int sg){
int x, y;
while(!Q.empty()){
pii t=Q.front();Q.pop();
x=t.first,y=t.second;
if(x==0||x==m-1||y==0||y==n-1){
if(str[x][y]=='0'||vis[x][y]==sg)return true;
}
for(int i=0;i<8;i++){
int cx=x+dx[i];
int cy=y+dy[i];
if(inside(cx,cy)&&!viss[cx][cy]&&(str[x][y]=='0'||vis[x][y]==sg)){
viss[cx][cy]=1;
Q.push({cx,cy});
// 走到0也走,只要能走出去
}
}
}
return false;
}
signed main(){
scanf("%d",&T);
while(T--){
memset(vis,0,sizeof(vis));
mp.clear();
scanf("%d %d",&m,&n);
for(int i=0;i<m;i++)cin>>str[i];
// dfs();
num=1;
for(int i=0;i<m;i++){
for(int j=0;j<n;j++){
if(str[i][j]-'0'==1&&!vis[i][j])vis[i][j]=num,dfs(i,j),num++;
}
}
int cnt=0;
for(int i=0;i<m;i++){
for(int j=0;j<n;j++){
if(str[i][j]-'0'==1&&!mp[vis[i][j]]){
mp[vis[i][j]]=1;
while(!Q.empty()){
Q.pop();
}
memset(viss,0,sizeof(viss));
Q.push({i,j});
viss[i][j]=1;
bool f=bfs(vis[i][j]);
if(!f){
cnt++;
}
}
}
}
cout<<num-1-cnt<<endl;
}
return 0;
}
//错在,子岛的定义是,不被一个道阻拦,而被多个岛屿阻拦不算子岛
//2
//5 5
//01111
//11001
//10101
//10001
//11111
//5 6
//111111
//100001
//010101
//100001
//111111
G: 子串简写
猜猜坑在哪?c1可能等于c2 哈哈哈,把else if(str[i]==c2){
改成直接判断c2 if(str[i]==c2)
#include <bits/stdc++.h>
using namespace std;
#define int long long int
#define pii pair<int,int>
const int N=5e5+5;
int n,k;
int res=0;
string str;
char c1,c2;
//int suffix[N];//不用,后缀和可以通过前缀和得到 sum[n]-sum[i-1]
int sum1[N];
int sum2[N];
//Prefix suffix
signed main(){
scanf("%d",&k);
cin>>str;
getchar();
cin>>c1;
getchar();
cin>>c2;
int n=str.size();
str="#"+str;
for(int i=1;i<=n;i++){
sum1[i]=sum1[i-1];
sum2[i]=sum2[i-1];
if(str[i]==c1){
sum1[i]+=1;
}
else if(str[i]==c2){
sum2[i]+=1;
}
// cout<<sum2[i]<<" ";
}
// cout<<endl;
for(int i=1;i<=n;i++){
if(str[i]==c1){
int j=i+k-1;
if(j<=n)res+=sum2[n]-sum2[j-1];
// cout<<res<<" ";
}
}
cout<<res;
return 0;
}
H: 整数删除
虽然也没AC,但那天晚上,忘了sort(ans.begin(),ans.end(),cmp);
这句代码真的让人气急攻心!
当时混乱一片,忘记排序,为了迎合样例倒序输出TT
#include <bits/stdc++.h>
using namespace std;
#define int long long int
#define pii pair<int,int>
const int N=5e5+5;
int n,k,x;
int res=0;
typedef struct node{
int v,pos;
bool operator<(const node & p)const{
if(v==p.v)return pos>p.pos;
else return v>p.v;
}
}node;
vector<node> ans;
int add[N];//当即加上不太方便操作,等碰到再加
priority_queue<node > Q;//,vector<node>,greater<node>
bool cmp(node a,node b){
return a.pos<b.pos;
}
map<int,int> del;
signed main(){
scanf("%d %d",&n,&k);
for(int i=1;i<=n;i++){
scanf("%d",&x);
Q.push({x,i});
}
while(k--){
node t=Q.top();Q.pop();
int pos=t.pos;
if(!add[pos]){
int l=pos-1,r=pos+1;
while(del[r])r++;
while(del[l])l++;
add[l]+=t.v;
add[r]+=t.v;
// add[pos+1]+=t.v;
// add[pos-1]+=t.v;
//没有关系,即使相邻位置不存在或已经被删除,反正不会再碰到
// 但是最后因为要输出最终值,仍然在队列中的元素add的值需要加上
//错了,删除了元素之后,pos相邻的元素原下标就不一定是pos+-1
//删除元素的时候
del[pos]=1;
}
else{
t.v+=add[pos];
add[pos]=0;
Q.push(t);
k++;
}
// for(int i=1;i<=n;i++)cout<<add[i]<<" ";
// cout<<endl;
}
while(!Q.empty()){
node t=Q.top();Q.pop();
// if(add[t.pos])
t.v+=add[t.pos];
ans.push_back(t);
}
sort(ans.begin(),ans.end(),cmp);
for(int i=0;i<ans.size();i++)cout<<ans[i].v<<" ";
// cout<<res;
return 0;
}
//5 3
//1 4 2 8 7
I: 景区导游
6 4
1 2 1
1 3 1
3 4 2
3 5 2
4 6 3
2 6 5 1
暴力先行,第一次连Floyd都写不出来TT
二维空间爆了空间,最多3e7
,这里到了1e10
#include <bits/stdc++.h>
using namespace std;
//#define int long long int
#define pii pair<int,int>
const int inf=0x3f3f3f3f;
const int N=1e3+5;//开小一点能过部分样例,开大了直接爆
int n,kk,u,v,w;
int e[N][N];
int r[N];
signed main(){
scanf("%d %d",&n,&kk);
// memset(e,0x3f,sizeof(e));
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
if(i!=j)e[i][j]=0x3f3f3f3f;
}
}
for(int i=1;i<n;i++){
scanf("%d %d %d",&u,&v,&w);
e[u][v]=min(w,e[u][v]);
e[v][u]=min(w,e[v][u]);
// cout<<e[u][v]<<endl;
}
// cout<<e[1][2]<<endl;
for(int i=1;i<=kk;i++)scanf("%d",&r[i]);
for(int k=1;k<=n;k++){
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
if(e[i][k]+e[k][j]<e[i][j])e[i][j]=e[i][k]+e[k][j];
}
}
}
// for(int i=1;i<=n;i++){
// for(int j=1;j<=n;j++){
// cout<<e[i][j]<<" ";
// }
// cout<<endl;
// }
int res=0;
for(int j=1;j<kk;j++){
res+=e[r[j]][r[j+1]];
// cout<<res<<endl;
}
// cout<<res<<endl;
for(int i=1;i<=kk;i++){
int ans=res;
if(i-1>=1)ans-=e[r[i-1]][r[i]];
if(i+1<=kk)ans-=e[r[i]][r[i+1]];
if(i-1>=1&&i+1<=kk)ans+=e[r[i-1]][r[i+1]];
cout<<ans<<" ";
}
return 0;
}
//6 4
//1 2 1
//1 3 1
//3 4 2
//3 5 2
//4 6 3
//2 6 5 1
也才过24%,lca还不行?原来我会的只是简单粗暴版的lca
#include <bits/stdc++.h>
using namespace std;
//#define int long long int
#define pii pair<int,int>
const int N=1e5+5;
const int M=2e5+5;//注意是双向边,空间开小了也会wa很多
int n,kk,u,v,w;
struct node{
int to,nxt,w;
}e[M];
int head[N];
int cnt;
void add(int u,int v,int w){
e[++cnt].w=w;
e[cnt].to=v;
e[cnt].nxt=head[u];
head[u]=cnt;
}
int dep[N];
int fa[N];
int sum[N];//从根节点到这个节点路径的长度总和
void dfs(int u,int f){
fa[u]=f;
for(int i=head[u];i;i=e[i].nxt){
int to=e[i].to;
if(to==f)continue;
dep[to]=dep[u]+1;
sum[to]=sum[u]+e[i].w;
dfs(to,u);
}
}
int lca(int u,int v){
if(dep[u]<dep[v])swap(u,v);
while(dep[u]!=dep[v]){
u=fa[u];
}//现在处于同一高度了,找lca
while(u!=v){
u=fa[u];
v=fa[v];
}
return u;
}
int r[N];
int dist(int u,int v){//任意两点之间的距离
return sum[u]+sum[v]-2*sum[lca(u,v)];
}
signed main(){
scanf("%d %d",&n,&kk);
for(int i=1;i<n;i++){
scanf("%d %d %d",&u,&v,&w);
add(u,v,w);
add(v,u,w);
}
dep[1]=1;sum[1]=0;
dfs(1,0);
for(int i=1;i<=kk;i++)scanf("%d",&r[i]);
int res=0;
for(int j=1;j<kk;j++){
res+=dist(r[j],r[j+1]);
// cout<<res<<endl;
}
for(int i=1;i<=kk;i++){
int ans=res;
if(i-1>=1)ans-=dist(r[i-1],r[i]);
if(i+1<=kk)ans-=dist(r[i],r[i+1]);
if(i-1>=1&&i+1<=kk)ans+=dist(r[i-1],r[i+1]);
cout<<ans<<" ";
}
return 0;
}
倍增LCA/tarjan LCA
二进制拼凑的思想
11的二进制表示的最高1位就是8代表的这一位
if(dep[x]<dep[y]) swap(x,y);//先保证x比y更深,x往上跳
for(int i=20; i>=0; i--)
if(dep[f[x][i]]>=dep[y]) // 找到和y同高度的节点
x = f[x][i];
dep[f[x][i]]>=dep[y]
表示x跳了
2
i
2^i
2i步还是比y深,还要继续往上跳,一直跳到xy深度相等,为什么一定可以跳到相等的一层,因为任何正数都可以通过二进制数表示,由
2
i
2^i
2i 累加而成
如果还不相等,一起往上跳
跳到公共祖先的最下面一层,因为先大步跳,如果判断f[x][i]==f[y][i]
,那么到达的自然是公共祖先,但无法判断是否是最近公共祖先,但如果跳到公共祖先的下面一层,判断f[x][i]!=f[y][i]
,就很确定,上一层就是最近公共祖先
AC代码,dfs,bfs都嘚!
#include <bits/stdc++.h>
using namespace std;
#define int long long int
#define pii pair<int,int>
const int N=1e5+5;
const int M=2e5+5;//注意是双向边,空间开小了也会wa很多
int n,kk,u,v,w;
struct node{
int to,nxt,w;
}e[M];
int head[N];
int cnt;
void add(int u,int v,int w){
e[++cnt].w=w;
e[cnt].to=v;
e[cnt].nxt=head[u];
head[u]=cnt;
}
int dep[N];
//int fa[N];
int fa[N][25];//节点i向上跳2^j能到达的节点
int sum[N];//从根节点到这个节点路径的长度总和
void dfs(int u,int f){
// fa[u]=f;
// dep[u]=dep[f]+1;
fa[u][0]=f;
for(int i=1;i<=20;i++)fa[u][i]=fa[fa[u][i-1]][i-1];
// 首先,根节点需要最先初始化fa[root][0~20],其次如果放在循环里面对父节点更新u不合理
//两点,首先最先进的root需要得到fa,但根节点任何向上的祖先都只有0
//其次,每个节点都需要得到fa,要么每进入dfs获得,要么,根节点的每个孩子的孩子的……得到
for(int i=head[u];i;i=e[i].nxt){
int to=e[i].to;
if(to==f)continue;
sum[to]=sum[u]+e[i].w;
dep[to]=dep[u]+1;
// fa[u][0]=f;错误
// for(int i=1;i<=20;i++)fa[u][i]=fa[fa[u][i-1]][i-1];
// fa[to][0]=u;正确
// for(int i=1;i<=20;i++)fa[to][i]=fa[fa[to][i-1]][i-1];
dfs(to,u);
}
}
void bfs(int rt){
queue<int> Q;Q.push(rt);dep[rt]=1;
while(!Q.empty()){
int u=Q.front();Q.pop();
for(int i=head[u];i;i=e[i].nxt){
int to=e[i].to;
// if(dep[to])continue;
if(to==fa[u][0])continue;
sum[to]=sum[u]+e[i].w;
dep[to]=dep[u]+1;
fa[to][0]=u;
for(int i=1;i<=20;i++)fa[to][i]=fa[fa[to][i-1]][i-1];
Q.push(to);
}
}
}
int lca(int u,int v){
if(dep[u]<dep[v])swap(u,v);
for(int i=20;i>=0;i--){
if(dep[fa[u][i]]>=dep[v])u=fa[u][i];
}
if(u==v)return u;
for(int i=20;i>=0;i--){
// if(dep[fa[u][i]]!=dep[fa[v][i]])u=fa[u][i],v=fa[v][i];
if(fa[u][i]!=fa[v][i])u=fa[u][i],v=fa[v][i];
}
return fa[u][0];
}
int r[N];
int dist(int u,int v){//任意两点之间的距离
return sum[u]+sum[v]-2*sum[lca(u,v)];
}
signed main(){
scanf("%d %d",&n,&kk);
for(int i=1;i<n;i++){
scanf("%d %d %d",&u,&v,&w);
add(u,v,w);
add(v,u,w);
}
// dep[1]=1;sum[1]=0;
// dfs(1,0);
bfs(1);
for(int i=0;i<kk;i++)scanf("%d",&r[i]);
int res=0;
for(int j=0;j<kk-1;j++){
res+=dist(r[j],r[j+1]);
// cout<<res<<endl;
}
for(int i=0;i<kk;i++){
int ans=res;
// if(i-1>=1)ans-=dist(r[i-1],r[i]);
// if(i+1<=kk)ans-=dist(r[i],r[i+1]);
// if(i-1>=1&&i+1<=kk)ans+=dist(r[i-1],r[i+1]);
// 跳过i(i不是端点),等同于砍掉i-1->i和i->i+1,加上i-1->i+1
if (i && i != kk - 1) ans += dist(r[i - 1], r[i + 1]) - dist(r[i - 1], r[i]) - dist(r[i], r[i + 1]);
// 跳过i(i是左端点),等同于砍掉i->i+1
else if (!i) ans -= dist(r[i], r[i + 1]);
// 跳过i(i是右端点),等同于砍掉i-1->i
else ans -= dist(r[i - 1], r[i]);
cout<<ans<<" ";
}
return 0;
}
//6 4
//1 2 1
//1 3 1
//3 4 2
//3 5 2
//4 6 3
//2 6 5 1