洛谷多校第一周续

T122393 À la Volonté du Peuple

这题可以两种写法:

 点有两个最短路前驱会爆,
边不在最短路上会爆。
 
第一种方法:暴力枚举每一个边和点,复杂度是O(n+m),而不是O(n*n)的,因为n和m同阶,达不到n^n的复杂度。
如果这样会爆,跑最短路就直接爆了,spfa肯定是O(n^n)的。总复杂度O(n+m)
 
#include<bits/stdc++.h>
using namespace std;
#define pb push_back
const int inf=0x3f3f3f3f;
const int maxn=3e5+5;
struct edge{int v,w;edge(int a,int b){v=a,w=b;}};//v终点,w边权
struct node{
    int id,dis;//id点编号 dis暂时距离
    node(int a,int b){id=a,dis=b;}
    friend bool operator<(node a,node b){
    return a.dis>b.dis;//每次让距离小出队
    }
};
vector<edge>e[maxn];
int dis[maxn];//记录最短路
bool done[maxn];//记录是否找到最短路
    int n,m;
void dijkstra(){
    int s=1;//s起点 根据情况改
    for(int i=0;i<=n;i++)dis[i]=inf,done[i]=0;
    dis[s]=0;
    priority_queue<node>Q;
    Q.push(node(s,0));
    while(!Q.empty()){
    node u=Q.top();Q.pop();
    if(done[u.id])continue;
    done[u.id]=1;
    for(int i=0;i<e[u.id].size();i++){//遍历邻居
    edge y=e[u.id][i];
    if(done[y.v])continue;
    if(dis[y.v]>y.w+dis[u.id]){
    dis[y.v]=y.w+u.dis;
    Q.push(node(y.v,dis[y.v]));//更新最短路
    }
    }
    }
}
int main(){
    cin>>n>>m;
    while(m--){
    int a,b,c;
    scanf("%d %d %d",&a,&b,&c);
    e[a].pb(edge(b,c));
    if(a!=b)e[b].pb(edge(a,c));
    }
    dijkstra();
    int ans=0,cnt;
    for(int i=1;i<=n;i++){
        cnt=0;
    for(int j=0;j<e[i].size();j++){
    int y=e[i][j].v;
    if(dis[i]==dis[y]+e[i][j].w)cnt++;
    if(i>=y&&dis[i]<dis[y]+e[i][j].w&&dis[y]<dis[i]+e[i][j].w)ans++;
    }
    if(cnt>1)ans++;
    }
    cout<<ans<<endl;
    return 0;
}
View Code

第二种方法:

比较鬼。

最短路前驱为1,不炸。
最短路前驱>=2,会少炸x-1次

考虑这样理解:
如果开始所有点used都为0,那么m条边都会炸,即ans=m;
对边而言
一个边如果炸了(不在最短路上),对边的两端used必然贡献为0,因为两边都不能更新最短路,都不会有最短路前驱
如果一个边不炸(在最短路上),那么必然会对一个点的used+1,也就是说不炸的边等价于used总和
即ans-=used[i];
对点而言
如果used>=2会炸,ans++;
总结一下:
ans=m
for i ans-=used
for i used>=2 ans++

#include<bits/stdc++.h>
using namespace std;
#define pb push_back
const int inf=0x3f3f3f3f;
const int maxn=3e5+5;
struct edge{int v,w;edge(int a,int b){v=a,w=b;}};//v终点,w边权
struct node{
    int id,dis;//id点编号 dis暂时距离
    node(int a,int b){id=a,dis=b;}
    friend bool operator<(node a,node b){
    return a.dis>b.dis;//每次让距离小出队
    }
};
vector<edge>e[maxn];
int dis[maxn];//记录最短路
bool done[maxn];//记录是否找到最短路
int n,m;
int used[maxn];
void dijkstra(){
    int s=1;//s起点 根据情况改
    for(int i=0;i<=n;i++)dis[i]=inf,done[i]=0;
    dis[s]=0;
    priority_queue<node>Q;
    Q.push(node(s,0));
    while(!Q.empty()){
    node u=Q.top();Q.pop();
    if(done[u.id])continue;
    done[u.id]=1;
    for(int i=0;i<e[u.id].size();i++){//遍历邻居
    edge y=e[u.id][i];
    if(done[y.v])continue;
    if(dis[y.v]>y.w+dis[u.id]){
    dis[y.v]=y.w+u.dis;
    used[y.v]=1;
    Q.push(node(y.v,dis[y.v]));//更新最短路
    }
    else if(dis[y.v]==y.w+dis[u.id])used[y.v]++;
    }
    }

}
int main(){
    memset(used,0,sizeof used);
    cin>>n>>m;
    int ans=m;
    while(m--){
    int a,b,c;
    scanf("%d %d %d",&a,&b,&c);
    e[a].pb(edge(b,c));
    if(a!=b)e[b].pb(edge(a,c));
    }
    dijkstra();
    for(int i=1;i<=n;i++){if(used[i]>=2)used[i]--;ans-=used[i];}
    cout<<ans<<endl;
    // system("pause");
    return 0;
}
View Code

T122394 Billionaire

zeller公式二分出日期答案,或者暴力按月 跳优化。

#include<bits/stdc++.h>
using namespace std;
int getId(int y, int m, int d) {
    if (m < 3) {y --; m += 12;}
    return 365 * y + y / 4 - y / 100 + y / 400 + (153 * (m - 3) + 2) / 5 + d - 307;
}
vector<int> date(int id) {
    int x = id + 1789995, n, i, j, y, m, d;
    n = 4 * x / 146097;
    x -= (146097 * n + 3) / 4;
    i = (4000 * (x + 1)) / 1461001; x -= 1461 * i / 4 - 31;
    j = 80 * x / 2447; d = x - 2447 * j / 80; x = j / 11;
    m = j + 2 - 12 * x; y = 100 * (n - 49) + i + x;
    vector<int>v;
    v.push_back(y),v.push_back(m),v.push_back(d);
    return v;
}
int m;
const int maxn=1000000000;
bool check(int x){
    int sum=m+x*(x+1)/2;
    if(sum>=maxn)return 1;
    else return 0;
}
int main(){
    int t;
    cin>>t;
    while(t--){
    int ty,tm,td;
    scanf("%d %d %d %d",&m,&ty,&tm,&td);
    int id=getId(ty,tm,td);
    int l=0,r=sqrt(2e9);
    while(l<=r){
    int mid=(r+l)/2;
    if(check(mid))r=mid-1;
    else l=mid+1;
    }
    id+=l;
    vector<int>ans=date(id);
    printf("%d %d %d
",ans[0],ans[1],ans[2]);
    }
    // system("pause");
    return 0;
}
View Code
想的太多,做的太少;
原文地址:https://www.cnblogs.com/littlerita/p/12590363.html