zoukankan      html  css  js  c++  java
  • Codeforces Round #345 (Div. 2)

    居然有场中国下午场次的CF,猴开心啊,于是就报名了...

    结果被虐傻了...果然不能太激动啊...

    A题题目翻译挂了,少了一个无解的情况,导致机房前20Min没有一个人能过A题...直到后面有高人相助才过,好惨

    C题前面都开了long long,只有输出没开I64d,结果就丢了1206分...这什么鬼啊...

    D题敲了20min的程序结果挂了,于是删掉重打,打到要结束了才发现题目两个东西弄反了,然后仓促改了一改...呼,然后少改一个地方,然后一堆细节的东西也有问题...表示无奈

    A题:两个电池,每秒钟充电的话电量+1,不充电-2,一个<=0,就结束。问最多撑多久?

      感觉贪心就好,就是每次给电量小的+1,结果WA了!好吧,我觉得是我贪心可能有问题,于是我就打了一个大暴力,f[i][j]表示两个电池的状态,WA了!然后我放弃了,我吃饭去了...回来就有人说还有一句话你没看见。

      如果一个电池的电量=1,你必须给它充电。结果1 1输出是0...好坑啊...

    O(100^3)大暴力:

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    
    using namespace std;
    
    int f[210][110][110];
    
    int main(){
    #ifndef ONLINE_JUDGE
        freopen("A.in","r",stdin);
    #endif
    
        int a1,a2,t=0;
    
        scanf("%d%d",&a1,&a2);
        if(a1==1 && a2==1){ printf("0");return 0; }
        f[0][a1][a2]=1;
        f[0][a2][a1]=1;
    
        for(int i=0;i<=200;i++)
            for(int j=1;j<=102;j++)
                for(int k=1;k<=102;k++)
                    if(f[i][j][k]){
                        if(j>2)
                            f[i+1][j-2][k+1]=1;
                        if(k>2)
                            f[i+1][j+1][k-2]=1;
                    }
        for(int i=200;i>=0;i--){
            for(int j=1;j<=100;j++)
                for(int k=1;k<=100;k++)
                    if(f[i][j][k]){
                        printf("%d",i+1);return 0;
                    }
        }
    
        return 0;
    }
    View Code

     O(100)的贪心,也可以过。

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    
    using namespace std;
    
    int main(){
    #ifndef ONLINE_JUDGE
        freopen("A.in","r",stdin);
    #endif
    
        int a,b,t=0;
    
        scanf("%d%d",&a,&b);
        if(a==1 && b==1){
            printf("0");return 0;
        }
    
        while(a>0 && b>0){
            if(a>b) swap(a,b);
            a++,b-=2;t++;
        }
        
        printf("%d",t);
        return 0;
    }
    View Code

    B题:给你n个序列,然后让你找到一种排列方式,使得ai<ai+1的数目最多。n<=1000,ai<=1000

      好吧,这题当时只想到暴力,唔暴力就是1000*1000,如果这个值有,那么就接在前面的放上这个。最后在得到的序列中暴力算一下。

      然后考完,唔,zyj说这题可以直接n-出现次数最多的元素,好神啊...相当于最小链覆盖=最长反链长度[我怎么会想到导弹拦截去...2333],如果还没理解这个做法的话,就可以脑补一下,发现除了这个出现次数最多的,其它的都可以找到贡献[可以往前也可以往后找贡献]。

      

    O(1000^2)大暴力:

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    
    using namespace std;
    
    const int maxn=1010;
    
    int n,k,ans;
    int a[maxn],b[maxn];
    int T[maxn];
    
    int main(){
    #ifndef ONLINE_JUDGE
        freopen("B.in","r",stdin);
    #endif
    
        scanf("%d",&n);
        for(int i=1;i<=n;i++)
            scanf("%d",&a[i]),T[a[i]]++;
        for(int i=1;i<=1000;i++)
            for(int j=1;j<=1000;j++){
                if(T[j]) T[j]--,b[++k]=j;
            }
        for(int i=1;i<=k;i++)
            if(b[i]<b[i+1]) ans++;
        printf("%d",ans);
        return 0;
    }
    View Code

    O(1000)的神奇做法

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    
    using namespace std;
    
    const int maxn=1010;
    
    int n,Max;
    int a[maxn],T[maxn];
    
    int main(){
    #ifndef ONLINE_JUDGE
        freopen("B.in","r",stdin);
    #endif
    
        scanf("%d",&n);
        for(int i=1;i<=n;i++){
            scanf("%d",&a[i]),T[a[i]]++;
            Max=max(Max,T[a[i]]);
        }
        printf("%d",n-Max);
        return 0;
    }
    View Code

    C题:给你n个点,求有多少点对的欧几里得距离=曼哈顿距离

      这就是问有多少点对在同一行或者同一列,然后*C(这一行/列上点数目,2)就是这一行/列上点对的数量。

      然后还要删掉重合的点的贡献,考试时最后一步没有输出long long导致崩盘。

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    
    using namespace std;
    
    const int maxn=200010;
    typedef long long ll;
    
    struct Point{
        int x,y;
    }s[maxn];
    
    bool cmp(const Point &A,const Point &B){
        return A.x<B.x;
    }
    
    bool cmp2(const Point &A,const Point &B){
        return A.y<B.y;
    }
    
    bool cmp3(const Point &A,const Point &B){
        if(A.x!=B.x) return A.x<B.x;
        return A.y<B.y;
    }
    
    int n;
    ll ans;
    
    int main(){
    #ifndef ONLINE_JUDGE
        freopen("C.in","r",stdin);
    #endif
    
        int cnt;
    
        scanf("%d",&n);
        for(int i=1;i<=n;i++)
            scanf("%d%d",&s[i].x,&s[i].y);
        
        sort(s+1,s+n+1,cmp);
        s[n+1].x=s[n+1].y=-1e9;
        for(int i=1;i<=n;i++){
            cnt=1;
            while(s[i].x==s[i+1].x) cnt++,i++;
            ans+=(ll)cnt*(cnt-1)/2;
        }
        sort(s+1,s+n+1,cmp2);
        for(int i=1;i<=n;i++){
            cnt=1;
            while(s[i].y==s[i+1].y) cnt++,i++;
            ans+=(ll)cnt*(cnt-1)/2;
        }
        sort(s+1,s+n+1,cmp3);
        for(int i=1;i<=n;i++){
            cnt=1;
            while(s[i].y==s[i+1].y && s[i].x==s[i+1].x) cnt++,i++;
            ans-=(ll)cnt*(cnt-1)/2;
        }
        
        printf("%I64d",ans);
        return 0;
    }
    View Code

    D题:有n张图片,你可以向左或者向右滑,每次滑需要a秒,看一张横着的图片需要1秒,一张竖着的图片需要1+b秒。如果现在看的图片之前没有看过,那么必须花时间看完它;如果已经看过,可以不花时间在看它上。你一开始在1号图片,问T秒最多看多少图片。

      根据题目信息,这题应该是看一段前缀+一段后缀,那么通过类似贪心的想法来找到最优的值。

      首先贪心找到后缀最远的,同时尝试往前拓展找到这个后缀对应的最远的前缀。然后每次后缀指针往后挪一个,前面的指针跟着动,然后更新答案就行了。而我可以通过比较前缀和后缀的长度来确定一开始翻的方向。

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    
    using namespace std;
    
    const int maxn=2000010;
    
    typedef long long ll;
    
    int n,l,r,a,b,T,ans;
    ll s1[maxn],s2[maxn];
    char ch[maxn];
    
    int main(){
    #ifndef ONLINE_JUDGE
        freopen("D.in","r",stdin);
    #endif
        
        scanf("%d%d%d%d",&n,&a,&b,&T);
        scanf("%s",ch+1);
        
        if(ch[1]=='w') T-=1+b;
        else T-=1;
        
        if(T<0){printf("0");return 0;}
        ans=1;l=1;r=n+1;
        
        for(int i=2;i<=n;i++)
            if(ch[i]=='w') s1[i]=s1[i-1]+1+b;
            else s1[i]=s1[i-1]+1;
        
        for(int i=n;i>=2;i--){
            if(ch[i]=='w') s2[i]=s2[i+1]+1+b;
            else s2[i]=s2[i+1]+1;
            if(T>=s2[i]+(n-i+1)*a) r=i;
        }
        
        if(r==2){printf("%d",n);return 0;}
    
        for(int i=2;i<=n;i++)
            if(i-1>(n-r+1)){
                if(T>=s1[i]+s2[r]+((n-r+1)<<1)*a+(i-1)*a) l=i;
                else break;
            }
            else{
                if(T>=s1[i]+s2[r]+((i-1)<<1)*a+(n-r+1)*a) l=i;
                else break;
            }
        
        ans=l+(n-r+1);
        
        int t;
        
        while(r<=n){
            r++;
            while(l<n){
                if(l>(n-r+1)){
                    if(T>=s1[l+1]+s2[r]+((ll)(n-r+1)<<1)*a+l*a) l++;
                    else break;
                }
                else{
                    if(T>=s1[l+1]+s2[r]+((ll)l<<1)*a+(n-r+1)*a) l++;
                    else break;
                }
            }
            ans=max(ans,l+n-r+1);
        }
        
        
        printf("%d",ans);
        
        return 0;
    }
    View Code

    E题:有个n*m的矩阵要求你将这个矩阵压缩成一个n*m的矩阵,但是要保证每行每列上的权值的相对大小不变。保证相对大小不变的基础上要求最大值最小,求这个压缩后的矩阵。

      我们可以首先将所有元素排一个序,然后每次取出最小的那个,一开始显然标号是1,然后之后的就看和这一行这一列上的关系,如果比这行/列上的元素大,那么就取这行/列上的元素+1;当然对于行列也要取最大值。

      然后因为相等的关系也要保证,所以我们可以用并查集把同一行同一列的相同元素连起来,然后定根的时候,统一取大的作为根,那么查询的时候就会查到这个元素的值了。

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    
    using namespace std;
    
    const int maxn=1000010;
    
    inline int in(){
        int x=0;char ch=getchar();
        while(ch>'9' || ch<'0') ch=getchar();
        while(ch>='0' && ch<='9') x=x*10+ch-'0',ch=getchar();
        return x;
    }
    
    struct Node{
        int x,y,v;
        Node(){}
        Node(int a,int b,int c){x=a,y=b,v=c;}
    }s[maxn];
    
    int n,m,tot;
    int a[maxn],b[maxn];
    int row_mx[maxn],cur_mx[maxn];
    int p[maxn];
    
    bool cmp(const Node &A,const Node &B){
        return A.v<B.v;
    }
    
    inline int Find(int x){
        int r=x,pre;
        while(r!=p[r]) r=p[r];
        while(x!=r){
            pre=p[x],p[x]=r,x=pre;
        }
        return r;
    }
    
    int main(){
    #ifndef ONLINE_JUDGE
        freopen("E.in","r",stdin);
    #endif
    
        n=in();m=in();
        for(int i=1;i<=n;i++)
            for(int j=1;j<=m;j++)
                a[++tot]=in(),s[tot]=Node(i,j,a[tot]);
    
        sort(s+1,s+tot+1,cmp);
        
        for(int i=1;i<=tot;i++) p[i]=i;
        for(int i=1;i<=tot;i++){
            int x=s[i].x,y=s[i].y,v=s[i].v;
            int id=(x-1)*m+y,t1=0,t2=0;
            
            int fx=Find(row_mx[x]),fy=Find(cur_mx[y]);
            
            if(v>a[fx]) t1++;
            if(v>a[fy]) t2++;
            
            b[id]=max(b[fx]+t1,b[fy]+t2);
            
            if(v==a[fx]){
                int f=Find(id);
                if(b[f]>b[fx]) p[fx]=f;
                else p[f]=fx;
            }
            
            if(v==a[fy]){
                int f=Find(id);
                if(b[f]>b[fy]) p[fy]=f;
                else p[f]=fy;
            }
            
            row_mx[x]=cur_mx[y]=Find(id);
            
        }
        
        int ip=0;
        for(int i=1;i<=n;i++){
            for(int j=1;j<=m;j++)
                printf("%d ",b[Find(++ip)]);
            putchar('
    ');
        }
        return 0;
    }
    View Code
  • 相关阅读:
    HDU2602:Bone Collector
    HDU5773:The All-purpose Zero
    LightOJ 1275:Internet Service Providers
    8.SpringMVC拦截器
    7.SpringMVC和Ajax技术
    Tomcat什么时候需要restart,redeploy,update classes and resources
    6.SpringMVC的JSON讲解
    5.SpringMVC数据处理
    4.SpringMVC的结果跳转方式
    3.SpringMVC的Controller 及 RestFul风格
  • 原文地址:https://www.cnblogs.com/Robert-Yuan/p/5252267.html
Copyright © 2011-2022 走看看