9.13省选模拟赛

题目就是2017NOI Day 1三道题。
能量采集
超级钢琴
海拔
第一题:用欧拉函数性质:一个数的所有因数的欧拉函数之和即该数,也可以用容斥原理。
再说一遍:大int乘以大int一定要转longlong!!!!!!!!

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
typedef long long ll;
const int MAXN=1e5+5;
int n,m,prime[MAXN],tot=0;
bool vis[MAXN];
ll ans,phi[MAXN];
inline void linear_shaker() {
    memset(vis,false,sizeof(vis));
    phi[1]=1;
    for (register int i=2;i<MAXN;++i) {
        if (!vis[i]) prime[++tot]=i,phi[i]=i-1;
        for (int j=1;j<=tot&&i*prime[j]<MAXN;++j) {
            vis[i*prime[j]]=true;
            if (i%prime[j]==0) {phi[i*prime[j]]=phi[i]*prime[j];break;}
            phi[i*prime[j]]=phi[i]*(prime[j]-1);
        }
    }
    for (register int i=2;i<MAXN;++i) phi[i]+=phi[i-1];
}
int main() {
    freopen("energy.in","r",stdin);
    freopen("energy.out","w",stdout);
    linear_shaker();
    while (~scanf("%d%d",&n,&m)) {
        ans=0;
        int last=0,t=min(n,m);
        for (int i=1;i<=t;i=last+1) {
            last=min(n/(n/i),m/(m/i));
            ans+=(phi[last]-phi[i-1])*(n/i)*(m/i);
        }
        cout<<(ans<<1)-1ll*n*m<<endl;//1ll?????!!!!!
    }
    return 0;
}

第二题:RMQ+堆
新技能get!如何求长度为L~R的最大连续子段和
固定左端点 i,用st表维护每一个[i,i+L-1]~[i,i+R-1]的前缀和最大值
然后用大根堆维护,每取一个元素,增加两个可行元素(具体见代码)

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<queue>
#include<cmath>
using namespace std;
typedef long long ll;
typedef pair<int ,int > pa;
const int MAXN=5e5+2;
pa mx[MAXN][21];int lg[MAXN];
int n,K,L,R,sum[MAXN];
ll ans=0;
struct NODE {
    int id,l,r,w,p;
    NODE(int _id,int _l,int _r,int _w,int _p):id(_id),l(_l),r(_r),w(_w),p(_p) {}
    friend bool operator <(const NODE &a,const NODE &b) {
        return a.w<b.w;
    }
};
priority_queue<NODE> q;
void init_st() {
    for (register int i=1;i<=n;++i)
        mx[i][0].first=sum[i],mx[i][0].second=i,lg[i]=(int)log2(i);
    for (int i=1;(1<<i)<=n;++i)
        for (register int j=1;j+(1<<i)-1<=n;++j)
            mx[j][i]=max(mx[j][i-1],mx[j+(1<<i-1)][i-1]);
}
pa query(int l,int r) {
    int t=lg[r-l+1];
    return max(mx[l][t],mx[r-(1<<t)+1][t]);
}
inline int read() {
    int x=0,f=1;char c=getchar();
    while (c<'0'||c>'9') {if (c=='-') f=-1;c=getchar();}
    while (c>='0'&&c<='9') x=x*10+c-'0',c=getchar();
    return x*f;
}
int main() {
    freopen("piano.in","r",stdin);
    freopen("piano.out","w",stdout);
    n=read(),K=read(),L=read(),R=read(),sum[0]=0;
    for (register int i=1;i<=n;++i) sum[i]=read()+sum[i-1];
    init_st();
    for (register int i=1;i+L-1<=n;++i) {
        int l=i+L-1,r=min(n,i+R-1);
        pa t=query(l,r);
        q.push(NODE(i,l,r,t.first-sum[i-1],t.second));
    }
    for (register int f=0;f<K;++f) {
        NODE nd=q.top();q.pop();
        ans+=nd.w;
        if (nd.l<nd.p) {
            pa t=query(nd.l,nd.p-1);
            q.push(NODE(nd.id,nd.l,nd.p-1,t.first-sum[nd.id-1],t.second));
        }
        if (nd.p<nd.r) {
            pa t=query(nd.p+1,nd.r);
            q.push(NODE(nd.id,nd.p+1,nd.r,t.first-sum[nd.id-1],t.second));
        }
    }
    cout<<ans<<endl;
    return 0;
}

第三题:平面图最小割转对偶图最短路
这个还真不会,只是在bzoj1001见过(没做)。目前只能感性理解,详细讲解戳这里

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<queue>
using namespace std;
typedef long long ll;
const int MAXN=505,INF=0x3f3f3f3f;
int n,dis[MAXN*MAXN],source,sink,t;
int head[MAXN*MAXN],edge=0;
struct EDGE {
    int v,nxt,w;
}e[MAXN*MAXN<<2];
bool vis[MAXN*MAXN];
struct NODE {
    int id,dis;
    NODE (int _id,int _dis):id(_id),dis(_dis) {}
    friend bool operator <(const NODE &a,const NODE &b) {
        return a.dis>b.dis;
    }
};
priority_queue<NODE> q;
inline int read() {
    int x=0,f=1;char c=getchar();
    while (c<'0'||c>'9') {if (c=='-') f=-1;c=getchar();}
    while (c>='0'&&c<='9') x=x*10+c-'0',c=getchar();
    return x*f;
}
inline void adde(int u,int v,int w) {
    e[edge].nxt=head[u],e[edge].v=v,e[edge].w=w,head[u]=edge++;
}
inline int num(int x,int y) {
    if (y==0||x==n+1) return source;
    if (x==0||y==n+1) return sink;
    return (x-1)*n+y;
}
inline void dijkstra() {
    memset(vis,false,sizeof(vis));
    memset(dis,127/3,sizeof(dis));
    dis[source]=0,q.push(NODE(source,0));
    while (!q.empty()) {
        NODE a=q.top();q.pop();
        int p=a.id;
        if (!vis[p]) {  
            vis[p]=true;
            for (int i=head[p];~i;i=e[i].nxt) {
                int v=e[i].v;
                if (dis[v]>dis[p]+e[i].w) {
                    dis[v]=dis[p]+e[i].w;
                    q.push(NODE(v,dis[v]));
                }
            }
        }
    }
}
int main() {
    freopen("altitude.in","r",stdin);
    freopen("altitude.out","w",stdout);
    memset(head,-1,sizeof(head));
    n=read(),source=0,sink=n*n+1;
    for (int i=0;i<=n;++i) for (int j=1;j<=n;++j) t=read(),adde(num(i+1,j),num(i,j),t);
    for (int i=1;i<=n;++i) for (int j=0;j<=n;++j) t=read(),adde(num(i,j),num(i,j+1),t);
    for (int i=0;i<=n;++i) for (int j=1;j<=n;++j) t=read(),adde(num(i,j),num(i+1,j),t);
    for (int i=1;i<=n;++i) for (int j=0;j<=n;++j) t=read(),adde(num(i,j+1),num(i,j),t);
    dijkstra();
    printf("%d\n",dis[sink]);
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值