1
18
2016
1

codeforces 100812

下午打了场gym,撸文化课笔记心累就随便写一写吧。

本人能力有限,只放我做了的几道。

http://codeforces.com/gym/100812

B set of tasks

题意杀,一开始以为是要求什么距离和最小这种很傻的东西怒WA一发然后又被阳神训斥了

阳神说题意是有5000个长度5000的01串,要你找出现次数最多的一个输出,要求这个01串里1不能超过15个或小于8个并没有什么卵用直接HASH或者map乱搞应该就能过,其实bitset排序硬上O(5000/32*5000*log(5000))应该也不怂但是撸完G题还有15分钟就没写

D dream of sum

一个序列要你求最短和为0的子序列。Map或者hash链乱搞,懒得写这两个就排序了沙雕题WA3发

 

#include<cstdio>
#include<algorithm>
using namespace std;
long long sum;
struct ele{
    long long s;
    int k;
}e[200005];
int n,x,cnt,ans1,ans2;
inline bool cmp(ele k1,ele k2){
    if(k1.s!=k2.s)return k1.s<k2.s;
    else return k1.k<k2.k;
}
int main(){
    scanf("%d",&n);
    for(int i=1;i<=n;i++){
        scanf("%d",&x);
        sum+=x;
        e[i].k=i;
        e[i].s=sum;
    }
    sort(e,e+1+n,cmp);
    ans2=n+2;
    for(int i=1;i<=n;i++)if(e[i].s==e[i-1].s){
        if(e[i].k-e[i-1].k<ans2){
            ans1=e[i-1].k+1;
            ans2=e[i].k-e[i-1].k;
        }
    }
    if(ans2==n+2)printf("-1");
    else printf("%d %d\n",ans1,ans2);
}

E world of knights

一开始把题名看成了world of knives觉得好中二

有若干张牌,有两个属性ai,bi,初始你有一张属性为0,1的牌,然后你可以用手里的一张牌i来获得另外一张牌j,满足bi>=aj,求获得第n张牌的最小操作数(即你最少要拿几张牌来获得第n张牌)并输出方案。

一开始以为是什么单点修改然后线段树求最小值这种东西。线段树已经打好了一看,这TM不是个SB单调栈吗(╯‵□′)╯︵┻━┻。然后怒打单调栈沙雕题又怒WA一发

 

#include<cstdio>
#include<algorithm>
#define inf 2000000000
#define lson index<<1
#define rson index<<1
using namespace std;
int n,stack[100005],pre[100005],top,cnt;
struct ele{
    int a,b,pre,k;
}e[100005],E[100005];
bool cmp(ele k1,ele k2){
    if(k1.a!=k2.a)return k1.a<k2.a;
    else return k1.b>k2.b;
}
void print(int k,int s){
    if(k){
        print(e[k].pre,s+1);
        printf("%d ",e[k].k);
    }else printf("%d\n",s);
}
int main(){
    scanf("%d",&n);
    for(int i=1;i<=n;i++)scanf("%d%d",&E[i].a,&E[i].b),E[i].k=i;
    if(n==1){
        if(E[1].a==0)printf("1\n1");
        else printf("No such luck");
        return 0;
    }
    sort(E+1,E+n,cmp);
    cnt=1;e[1]=E[1];
    for(int i=2;i<n;i++)if((E[i].a>e[cnt].a)&&(E[i].b>e[cnt].b)){
        cnt++;
        e[cnt]=E[i];
    }
    e[0].a=0;e[0].b=1;top=1;stack[1]=0;
    for(int i=1;i<=cnt;i++){
        if(e[i].a>e[i].b)continue;
        int l=0,r=top+1;
        while(r-l>1){
            int mid=(l+r)>>1;
            if(e[stack[mid]].b>=e[i].a)r=mid;
            else l=mid;
        }
        if(r==top+1)continue;
        e[i].pre=stack[r];
        top++;
        stack[top]=i;
    }
    int l=0,r=top+1;
    while(r-l>1){
        int mid=(l+r)>>1;
        if(e[stack[mid]].b>=E[n].a)r=mid;
        else l=mid;
    }
    if(r==top+1){
        printf("No such luck");
        return 0;
    }else{
        print(stack[r],1);
        printf("%d",n);
    }
}

F Graveyard of Bandits

题意给你一个n*m的*.矩阵,你可以在所有.的地方建墓碑,问你建1*1,1*2,1*3...1*max(n,m)的矩阵的方案数。

第一眼看n,m<=105吓了一跳,发现后面还有一个n*m<=106

统计出来图中所有1*1,1*2,1*3,...,1*max(n,m)的独立矩阵数(这些矩阵不能再合并成1*k),显然在一个1*i的矩阵里选一个1*j的矩阵方案是i-j+1种,前缀和乱搞搞就行,然后这样做一遍就能得到所有横着建的方案数。

然后1*1,2*1,3*1,...,max(n,m)*1竖着再搞一遍就好了,注意1*1会算两次特判掉。

 

#include<cstdio>
using namespace std;
int n,m;
char c[1000005];
int ans[100005];
long long A[100005];
inline int max(int x,int y){return x>y?x:y;}
int main(){
    scanf("%d%d",&n,&m);
    for(int i=0;i<n;i++)scanf("%s",c+i*m);
    for(int i=0;i<n;i++){
        int s=0;
        for(int j=0;j<m;j++)if(c[i*m+j]=='.')s++;
        else{
            if(s)ans[s]++;
            s=0;
        }
        if(s)ans[s]++;
    }
    for(int j=0;j<m;j++){
        int s=0;
        for(int i=0;i<n;i++)if(c[i*m+j]=='.')s++;
        else{
            if(s)ans[s]++;
            s=0;
        }
        if(s)ans[s]++;
    }
    long long Ans=0,sum=0;
    for(int i=max(n,m);i;i--){
        sum+=ans[i];
        Ans+=sum;
        if(i>1)A[i]=Ans;
        else A[i]=Ans/2;
    }
    for(int i=1;i<=max(n,m);i++)printf("%I64d ",A[i]);
}

G short path

吃完饭做的,所以没有时间打B了。

题意:给你一个20W点10W边的图,其中某些点有标记,求有标记的点之中的两点最短距离。

看边比较小感觉标算应该很巧妙,不是很会来,直接上k次SPFA,k次v全部初始化显然T,所以打了时间戳。

跑80点啥事没有很开心,然后TLE101CF卡SPFA丧心病狂

然后上读入优化还是TLE101,然后

 

        if(clock()>=1800){
            if(ans==1LL*n*1000000000)printf("No luck at all");
            else printf("%I64d\n%d %d",ans,x,y);
            return 0;
        }

A掉了

#include<cstdio>
#include<ctime>
using namespace std;
int f[200005],head[200005],dl[200005],B[200005];
long long v[200005];
int n,m,x,y,l,r,times,cnt;
bool b[200005];
long long ans;
struct edge{
    int next,to,l;
}e[200005];
inline long long min(long long x,long long y){return x<y?x:y;}
void add(int x,int y,int l){
    cnt++;
    e[cnt].next=head[x];
    e[cnt].to=y;
    e[cnt].l=l;
    head[x]=cnt;
}
inline int read(){
    int ret=0;
    char c=getchar();
    while((c>'9')||(c<'0'))c=getchar();
    while((c>='0')&&(c<='9'))ret=(ret<<1)+(ret<<3)+c-'0',c=getchar();
    return ret;
}
void spfa(int root){
    times++;B[root]=times;
    v[root]=0;
    l=r=1;dl[1]=root;b[root]=true;
    while(true){
        if((f[dl[l]])&&(dl[l]!=root)&&(ans>v[dl[l]])){
            ans=v[dl[l]];
            x=root;
            y=dl[l];
        }
        for(int i=head[dl[l]];i;i=e[i].next)if(((B[e[i].to]<times)||(v[e[i].to]>v[dl[l]]+e[i].l))&&(v[dl[l]]+e[i].l<ans)){
            B[e[i].to]=times;
            v[e[i].to]=v[dl[l]]+e[i].l;
            if(!b[e[i].to]){
                r++;
                if(r>n)r=1;
                dl[r]=e[i].to;
                b[e[i].to]=true;
            }
        }
        b[dl[l]]=false;
        if(r==l)break;
        l++;
        if(l>n)l=1;
    }
}
int main(){
    n=read();m=read();
    for(int i=1;i<=n;i++)f[i]=read();
    while(m--){
        x=read();y=read();l=read();
        add(x,y,l);
        add(y,x,l);
    }
    ans=1LL*n*1000000000;
    for(int i=1;i<=n;i++)if(f[i]){
        spfa(i);
        if(clock()>=1800){
            if(ans==1LL*n*1000000000)printf("No luck at all");
            else printf("%I64d\n%d %d",ans,x,y);
            return 0;
        }
    }
    if(ans==1LL*n*1000000000)printf("No luck at all");
    else printf("%I64d\n%d %d",ans,x,y);
}

后来去看不知道是凌神还是YB的代码,这个东西好像只要BFS就行_(:зゝ∠)_果然还是我太沙雕的缘故

I Dragon Delivers

题意:给你若干个订单,每个订单可以有两种办法交付,第一种直接交付,代价为d,第二种和他之前第一个直接交付的订单合并,代价为(ti-tj)*c,求最小交付所有订单的方法。

dp方程很好写,dp[i]=min(dp[j]+(sum[i]-sum[j]-t[j+1]*(i-j))*c+d)感觉好像可以斜率优化。

一看数据范围,n=1k,呵呵。稍微处理一下就能去掉前缀和。

 

#include<cstdio>
#include<algorithm>
using namespace std;
int n,d,c;
int x[1005];
long long dp[1005];
int main(){
    scanf("%d%d%d",&n,&d,&c);
    dp[0]=0;
    for(int i=1;i<=n;i++)scanf("%d",&x[i]);
    for(int i=1;i<=n;i++){
        dp[i]=dp[i-1]+d;
        long long s=0;
        for(int j=i-1;j>=1;j--){
            s+=x[i]-x[j];
            dp[i]=min(dp[i],s*c+dp[j-1]+d);
        }
    }
    printf("%I64d\n",dp[n]);
}

J Feeling of Comradeship

初三大爷做的,我不知道。有需要的去问初三大爷一号

L Knights without Fear and Reproach

题意:有两个人一起打你,第一个人每a秒打你一下,第二个人每b秒打你一下,你假如有两秒之内被打两次就GG,问你什么时候会GG。

一眼感觉好厉害,第二眼沙雕题,只有两种可能exgcd或者lcm,别和我说你不会。

注意特判a,b里有1的情况,我没特判怒WA一发_(:зゝ∠)_

 

#include<cstdio>
#include<algorithm>
using namespace std;
int a,b,gcd,x,y,A,B;
long long ans;
inline int exgcd(int x, int y, int&a, int&b)  {
    if(y==0){
        a=1,b=0;  
        return x;
    }
    int g=exgcd(y,x%y,a,b);  
    int t=a;
    a=b;  
    b=t-x/y*b;  
    return g;  
}  
int main(){
    scanf("%d%d",&x,&y);
    if((x==1)&&(y==1)){
        printf("1");
        return 0;
    }
    if((x==1)||(y==1)){
        printf("2");
        return 0;
    }
    int gcd=exgcd(x,y,a,b);
    ans=1LL*x*y/gcd;
    if(gcd>1){
        printf("%I64d",ans);
        return 0;
    }
    if(a>0)ans=min(ans,1LL*a*x);
    else ans=min(ans,1LL*b*y);
    printf("%I64d\n",ans);
}

1、文化课积重难返心累啊

2、哲教阳神YB一群人看我和初三大爷在打gym就来殴打小盆友简直丧心病狂

Category: codeforces | Tags: Gym | Read Count: 2455
Avatar_small
繁星 说:
2016年2月01日 22:02

你就不能好好叫我名字吗orz叫简拼也比这玩意好啊魂淡!(掀


登录 *


loading captcha image...
(输入验证码)
or Ctrl+Enter

Host by is-Programmer.com | Power by Chito 1.3.3 beta | Theme: Aeros 2.0 by TheBuckmaker.com