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;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章