汕头市队赛SRM15

T1——czl SRM 15

 众所周知,czl家养了一只可♂爱的***(已屏蔽),那只东西很贪吃,所以czl家很多零食仓库,然而这些仓库里有很多老鼠。

 为了心爱的***,czl决定点燃纯艾条,用烟熏老鼠。

 共有N个仓库,编号1-N。

 假设陵陵在第i个仓库点燃艾条,烟雾就会充满该仓库,并向左右扩散Ai 的距离,接着所有|i-j|<=Ai 的仓库 j 的老鼠被消灭。

 陵陵是个爱护环境的人,他想知道最少需要多少支艾条,才可以消灭所有老鼠。

 【输入格式】

 第一行:一个正整数,代表 N。

 第二行:N 个非负整数,第 i 个数代表 A i 。

 【输出格式】

 第一行:一个整数,代表答案。

 【样例】

 Inout:

5

2 3 3 3 3

Output:

1

【数据范围】

 20%的数据:N <= 20

 60%的数据:N <= 10^3

 100%的数据:N <= 5*10^5 ,Ai<=N

——————————————————————————

这道题就是用最少的线段覆盖整个区间

这题我写的贪心 把被包含的区间去掉之后 贪心做

#include<cstdio>
#include<algorithm>
#include<cstring>
#define LL long long
using namespace std;
const int M=1e6+7,inf=0x3f3f3f3f;
int read(){
    int ans=0,f=1,c=getchar();
    while(c<'0'||c>'9'){if(c=='-') f=-1; c=getchar();}
    while(c>='0'&&c<='9'){ans=ans*10+(c-'0'); c=getchar();}
    return ans*f;
}
int cnt,n,ans,f[M],h[M],q[M];
struct node{int l,r;}e[M];
bool cmp(node a,node b){return a.l!=b.l?a.l<b.l:a.r>b.r;}
int main()
{
    int k;
    n=read();
    for(int i=1;i<=n;i++) k=read(),e[i].l=max(1,i-k),e[i].r=min(i+k,n);
    sort(e+1,e+1+n,cmp); q[++cnt]=1;
    for(int i=2;i<=n;i++) if(e[i].r>e[q[cnt]].r) q[++cnt]=i;
    k=2; ans=1;
    int now=e[q[1]].r;
    while(k<=cnt){
        while(k<cnt&&e[q[k+1]].l<=now+1) k++;
        ans++; now=e[q[k]].r; k++;
    }printf("%d\n",ans);
    return 0;
}
View Code

T2——sxt SRM 15

为了加快社会主义现代化,建设新渔村,sxt决定给小渔村里每座建筑都连上互联网,方便未来随时随地网购西瓜肥料。

小渔村很大,有 N 座建筑,但地理位置偏僻,网络信号很差。

一座建筑有网,当且仅当满足以下至少一个条件:

1、给中国移动交宽带费,直接连网,花费为 A。

2、向另外一座有网的建筑,安装共享网线,花费为 B×两者曼哈顿距离。

现在,腾腾已经统计出了所有建筑的坐标。他想知道最少要多少费用才能达到目的。

【输入格式】

第一行:三个正整数,代表 N、A、B。

接下来 N 行:每行两个整数 X i 、Y i ,第 i 行代表第 i 座建筑的坐标。

【输出格式】

第一行:一个整数,代表答案。

【样例】

Input

3 3 2

1 1

0 1

0 0

Output

7

 

【数据范围】

30%的数据:N <= 3,A <= 50,B <= 5

60%的数据:N <= 100,A <= 1000,B <= 20

100%的数据:N <= 10^3 ,A <= 10^4 ,B <= 50,|Xi |,|Y i | < 2^15

——————————————————————————————————

这是道很裸的最小生成树了 直接加一个点 向其他1-n连大小为A的边就好了

我写的prim可能会快点

#include<cstdio>
#include<cstring>
#include<algorithm>
#define LL long long
using namespace std;
const int M=1e3+7;
const LL inf=1e15;
int read(){
    int ans=0,f=1,c=getchar();
    while(c<'0'||c>'9'){if(c=='-') f=-1; c=getchar();}
    while(c>='0'&&c<='9'){ans=ans*10+(c-'0'); c=getchar();}
    return ans*f;
}
int n,S,A,B,vis[M];
LL x[M],y[M],map[M][M],d[M],ans;
LL pabs(LL x){return x>=0?x:-x;}
LL calc(int s1,int s2){return pabs(x[s1]-x[s2])+pabs(y[s1]-y[s2]);}
void prim(){
    d[S]=0; vis[S]=1;
    for(int i=1;i<=n;i++) d[i]=map[S][i];
    for(int i=1;i<=n;i++){
        double mn=inf;
        int h=0;
        for(int j=1;j<=n;j++) if(!vis[j]&&mn>d[j]) mn=d[j],h=j;
        ans+=mn; d[h]=0; vis[h]=1;
        for(int j=1;j<=n;j++) if(!vis[j]&&map[h][j]<d[j]) d[j]=map[h][j];
    }
}

int main()
{
    n=read(); A=read(); B=read(); S=0;
    for(int i=1;i<=n;i++) x[i]=read(),y[i]=read();
    for(int i=1;i<=n;i++) map[S][i]=map[i][S]=A;
    for(int i=1;i<=n;i++) for(int j=i+1;j<=n;j++) map[i][j]=map[j][i]=B*calc(i,j);
    prim();
    printf("%lld\n",ans);
    return 0;
}
View Code

T3——yyl SRM 15

当了集训队爷后的yyl为了当上renying踏上了健身之路,他想让s(你可以认为这个是其他男同学的那啥)的值尽量少,以在妹子面前衬托他的健美。为了达到他的目的,他希望你对序列进行旋转操作,一次旋转操作可以使序列中的所有元素前移一位,并使 s1移动到 sn ,具体来说是这样的:

————————————————————————————————————-

这道题我们可以破环成链 每次相当于把1-n 挪一位相减求和

我们可以发现每个数对答案贡献的函数是线性的不然就是分段函数有个拐点(先递减后递增)

每一位的拐点等于 i+1-v【i】  如果小于0就是一直递增

然后每次移动区间维护一下各种信息就好辣

(zz地比赛没写出来 赛后调了一个多小时.QAQ

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#define LL long long
using namespace std;
const int M=4e6+7;
int read(){
    LL ans=0,f=1,c=getchar();
    while(c<'0'||c>'9'){if(c=='-') f=-1; c=getchar();}
    while(c>='0'&&c<='9'){ans=ans*10+(c-'0'); c=getchar();}
    return ans*f;
}
int n,m;
int v[M],f[M],cnt=1;
LL sum,ans,now;
struct node{int pos; LL h;}e[M];
bool cmp(node a,node b){return a.h<b.h;}
int main()
{
    n=read(); m=n<<1;
    for(int i=1;i<=n;i++) v[i]=read(),v[i+n]=v[i],sum+=abs(v[i]-i);
    for(int i=1;i<=m;i++) f[i]=-1,e[i].pos=i,e[i].h=i+1-v[i];//v[i]==y-x+1
    ans=sum; sort(e+1,e+1+m,cmp);
    while(e[cnt].h<=1&&cnt<=m) f[e[cnt].pos]=1,cnt++;
    for(int i=2;i<=n;i++) now+=f[i];
    for(int i=2;i<=n;i++){
        sum+=now;
        sum-=abs(v[i-1]-1);
        sum+=abs(v[i+n-1]-n);
        now-=f[i];
        while(e[cnt].h<=i&&cnt<=m){
            int x=e[cnt].pos; 
            cnt++; f[x]=1;
            if(i<x&&x<i+n-1) now+=2;
        } 
        now+=f[i+n-1];
        ans=min(ans,sum); 
    }printf("%lld\n",ans);
    return 0;
}
View Coded

当然因为 v【i】<=n 所以可以利用桶排算出每个值排序后在哪个区间,然后放进那个区间 这样就是o(n)了

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#define LL long long
using namespace std;
const int M=4e6+7;
int read(){
    LL ans=0,f=1,c=getchar();
    while(c<'0'||c>'9'){if(c=='-') f=-1; c=getchar();}
    while(c>='0'&&c<='9'){ans=ans*10+(c-'0'); c=getchar();}
    return ans*f;
}
int n,m;
int v[M],f[M],s[M],l[M],r[M],k,cnt=1;
LL sum,ans,now;
struct node{int pos; LL h;}e[M],q[M];
bool cmp(node a,node b){return a.h<b.h;}
int main()
{
    n=read(); m=n<<1;
    for(int i=1;i<=n;i++) v[i]=read(),v[i+n]=v[i],sum+=abs(v[i]-i);
    for(int i=1;i<=m;i++) f[i]=-1,e[i].pos=i,e[i].h=max(1,i+1-v[i]),s[e[i].h]++;//v[i]==y-x+1
    int last=0; for(int i=1;i<=m;i++)if(s[i]) l[i]=last+1,r[i]=last+s[i],last=r[i];
    for(int i=1;i<=m;i++) q[l[e[i].h]]=e[i],l[e[i].h]++;
    ans=sum; while(q[cnt].h<=1&&cnt<=m) f[q[cnt].pos]=1,cnt++;
    for(int i=2;i<=n;i++) now+=f[i];
    for(int i=2;i<=n;i++){
        sum+=now;
        sum-=abs(v[i-1]-1);
        sum+=abs(v[i+n-1]-n);
        now-=f[i];
        while(q[cnt].h<=i&&cnt<=m){
            int x=q[cnt].pos; 
            cnt++; f[x]=1;
            if(i<x&&x<i+n-1) now+=2;
        } 
        now+=f[i+n-1];
        ans=min(ans,sum); 
    }printf("%lld\n",ans);
    return 0;
}
View Code

 

posted @ 2017-08-22 20:12  友人Aqwq  阅读(204)  评论(0编辑  收藏  举报