Codeforces #291 Div 2 簡要題解

A. Chewbaсca and Number

題目鏈接

http://codeforces.com/contest/514/problem/A

題目大意

給你一個數字,你可以對其每一位進行翻轉操作:假如原來這個數字大小爲i ,翻轉後就變爲9i ,問翻轉後數字最小是多少

思路

水題

代碼

#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <algorithm>

#define MAXN 110

using namespace std;

int n;
char A[MAXN],B[MAXN];
char ans[MAXN];

int main()
{
    scanf("%s",A+1);
    n=strlen(A+1);
    if(9-(A[1]-'0')<=(A[1]-'0')&&(9-(A[1]-'0')))
        B[1]='0'+(9-(A[1]-'0'));
    else B[1]=A[1];
    for(int i=2;i<=n;i++)
    {
        if(9-(A[i]-'0')<=(A[i]-'0'))
            B[i]='0'+(9-(A[i]-'0'));
        else B[i]=A[i];
    }
    printf("%s\n",B+1);
    return 0;
}

B. Han Solo and Lazer Gun

題目鏈接

http://codeforces.com/contest/514/problem/B

題目大意

給你n 個點,問有多少個子集,使得子集裏每個點和(x0,y0) 都在同一直線上

思路

枚舉每個點,得到它們各自和(x0,y0) 的連線的斜率,然後用並查集合並斜率相同的點即可。

注意此題卡double精度,還有要注意分母爲0的情況,判斷斜率是否相同時最好做移項,使用整數運算,避免除法

代碼

#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <algorithm>
#include <cmath>

#define MAXN 1100
#define EPS 1e-10

using namespace std;

int n;
typedef pair<int,int> pr;
pr points[MAXN],center;

int f[MAXN];

int findSet(int x)
{
    if(f[x]==x) return f[x];
    return f[x]=findSet(f[x]);
}

int main()
{
    for(int i=1;i<MAXN;i++) f[i]=i;
    scanf("%d%d%d",&n,&center.first,&center.second);
    for(int i=1;i<=n;i++)
        scanf("%d%d",&points[i].first,&points[i].second);
    for(int i=1;i<=n;i++)
        for(int j=i+1;j<=n;j++)
        {
            if(!(points[i].second-center.second)||!(points[j].second-center.second)) continue;
            if((points[i].first-center.first)*(points[j].second-center.second)==(points[j].first-center.first)*(points[i].second-center.second))
            {
                f[findSet(i)]=f[findSet(j)];
            }
        }
    for(int i=1;i<=n;i++)
        for(int j=i+1;j<=n;j++)
        {
            if(!(points[i].second-center.second)&&!(points[j].second-center.second))
            {
                f[findSet(i)]=f[findSet(j)];
            }
        }
    int tot=0;
    for(int i=1;i<=n;i++)
    {
        if(findSet(i)==i) tot++;
    }
    printf("%d\n",tot);
    return 0;
}

C. Watto and Mechanism

題目鏈接

http://codeforces.com/contest/514/problem/C

題目大意

給你n 個字符串,m 次詢問一個串S ,是否能在原來n 個串中找到一個字符串,並在這個串裏修改一個字符,使得這個串和S 相同

思路

把所有的串插入進trie樹裏,然後每次詢問把S 串拿來在trie樹裏DFS,並記錄走到當前的trie結點時,是否已經修改過S 串裏的某個字符,如果匹配成功,且在遍歷過程中僅修改了一次S 串的字符,就表明能在原來n 個串中找到一個字符串,並在這個串裏修改一個字符,使得這個串和S 相同。

說起來比較繞口,還是看代碼比較清楚吧

代碼

#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <algorithm>
#include <cmath>

#define MAXN 610000
#define EPS 1e-10

using namespace std;

int n,m;
char s[MAXN];

int ch[MAXN][26],nCount=0,root=0;

void Insert()
{
    int len=strlen(s+1),p=root;
    for(int i=1;i<=len;i++)
    {
        if(!ch[p][s[i]-'a']) ch[p][s[i]-'a']=++nCount;
        p=ch[p][s[i]-'a'];
    }
}

int len;

bool DFS(int pos,int p,bool flag)
{
    bool sol=false;
    if(pos>len)
    {
        if(flag) return true;
        return false;
    }
    if(ch[p][s[pos]-'a'])
        if(DFS(pos+1,ch[p][s[pos]-'a'],flag))
           return true;
    if(!flag)
    {
        for(int i=0;i<26;i++)
            if(s[pos]-'a'!=i&&ch[p][i])
                if(DFS(pos+1,ch[p][i],true))
                    return true;
    }
    return false;
}

int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)
    {
        scanf("%s",s+1);
        Insert();
    }
    for(int i=1;i<=m;i++)
    {
        scanf("%s",s+1);
        len=strlen(s+1);
        if(DFS(1,root,false)) printf("YES\n");
        else printf("NO\n");
    }
    return 0;
}

D. R2D2 and Droid Army

題目鏈接

http://codeforces.com/contest/514/problem/D

題目大意

給你一個nm 列的表格,每次操作時你可以選擇其中一列,將這一列的元素全部減1(若某個元素爲0,減1後不變,仍然是0),你最多可以操作k 次,問操作完了以後,最多能有連續多少行的元素全部爲0,輸出一種可行方案。

思路

顯然操作k 次不會比操作少於k 次差。我們可以二分操作完了以後,最多能有連續多少行的元素全部爲0,這樣就轉變爲一個判定性問題:操作完了以後,是否最多能有連續mid 行的元素全部爲0。

我們可以O(nmid+1) 枚舉[L,R] 這段連續的行裏全部變爲0,顯然要想實現這個目標,必須得要做1jmmaxLiR{a[i][j]} 次操作,爲了快速求出這個值,我們可以建立m 個線段樹,分別維護每一列的區間最大值,然後就是查詢線段樹後做個求和就好了。1jmmaxLiR{a[i][j]}k ,就表明最多能有連續mid 行的元素全部爲0。

代碼

#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <algorithm>
#include <cmath>

#define MAXN 110000
#define EPS 1e-10

using namespace std;

int n,m,K;
int mat[MAXN][6];
int maxans,ans[6],sol[6];

struct Segtree
{
    int maxv[MAXN<<2];
    void Build(int o,int L,int R,int id)
    {
        if(L==R)
        {
            maxv[o]=mat[L][id];
            return;
        }
        int M=(L+R)>>1;
        Build(o<<1,L,M,id);
        Build(o<<1|1,M+1,R,id);
        maxv[o]=max(maxv[o<<1],maxv[o<<1|1]);
    }

    int query(int o,int L,int R,int ql,int qr)
    {
        if(ql<=L&&R<=qr)
            return maxv[o];
        int M=(L+R)>>1,ans=0;
        if(ql<=M) ans=max(ans,query(o<<1,L,M,ql,qr));
        if(qr>M) ans=max(ans,query(o<<1|1,M+1,R,ql,qr));
        return ans;
    }
}segt[6];

bool check(int len)
{
    for(int L=1,R=len;R<=n;L++,R++)
    {
        int sum=0;
        for(int i=1;i<=m;i++)
            sol[i]=segt[i].query(1,1,n,L,R);
        for(int i=1;i<=m;i++)
            sum+=sol[i];
        if(sum<=K) return true;
    }
    return false;
}

int main()
{
    scanf("%d%d%d",&n,&m,&K);
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
            scanf("%d",&mat[i][j]);
    for(int i=1;i<=m;i++)
        segt[i].Build(1,1,n,i);
    int lowerBound=1,upperBound=n;
    maxans=-1;
    while(lowerBound<=upperBound)
    {
        int mid=(lowerBound+upperBound)>>1;
        if(check(mid))
        {
            lowerBound=mid+1;
            maxans=mid;
            for(int i=1;i<=m;i++) ans[i]=sol[i];
        }
        else upperBound=mid-1;
    }
    if(maxans!=-1)
    {
        for(int i=1;i<=m;i++)
            printf("%d ",ans[i]);
        printf("\n");
    }
    else
    {
        for(int i=1;i<=m;i++)
            printf("0 ");
        printf("\n");
    }
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章