Codeforces Round #239 (Div. 1)

链接:http://codeforces.com/contest/407

A Triangle

给出直角三角形的两个直角边,构造出一个三角形顶点均为整数,且每条边不与xy轴平行。构成两个直角边的一定是勾股数。

int get(int x)
{
    if(x==1) return 1;
    if(!x||x==2||x==3) return 0;
    int t=sqrt(1.0*x)+3;
    while(t*t>x) t--;
    if(t*t==x) return t;
    return 0;
}

vector<pair<int,int > > cal(int n)
{
    vector<pair<int,int > > V;

    int i,j;
    for(i=1;i<n;i++)
    {
        int j=get(n*n-i*i);
        if(!j) continue;
        V.pb(MP(i,j));
    }
    return V;
}

int ok(int x1,int y1,int x2,int y2)
{
    if(x1*x2+y1*y2) return 0;
    if(x1==x2 || y1==y2) return 0;
    puts("YES");
    puts("0 0");
    PR(x1,y1);
    PR(x2,y2);
    return 1;
}

int ok(pair<int,int > a, pair<int,int > b)
{
    int x1=a.first;
    int y1=a.second;
    int x2=b.first;
    int y2=b.second;

    int dx[]={1,1,-1,-1};
    int dy[]={1,-1,1,-1};
    int i,j;
    FOR0(i,4) FOR0(j,4)
    {
        if(ok(x1*dx[i],y1*dy[i],y2*dx[j],x2*dx[j])) return 1;
        if(ok(y1*dx[i],x1*dy[i],x2*dx[j],y2*dx[j])) return 1;
    }
    return 0;
}

int main()
{
    int n,m;
    RD(n,m);
    vector<pair<int,int> > a=cal(n);
    vector<pair<int,int> > b=cal(m);
    if(SZ(a)==0 || SZ(b)==0)
    {
        puts("NO");
        return 0;
    }
    int i,j;
    FOR0(i,SZ(a)) FOR0(j,SZ(b)) if(ok(a[i],b[j])) return 0;
    puts("NO");
}

 

B Long Path

n+1个房间。第偶数次达到i则下一步到达i+1,否则下一步达到一个指定的房间a[i]=j(1<=j<=i)。从1出发到达n+1的步数。q[i]表示从1开始第一次到达i需要的步数,p[i]表示从1出发第二次到达i的步数,则q[i]=p[i-1]+1,p[i]=q[i]+1+p[a[i]]-q[a[i]]+1+p[i-1]-p[a[i]]。

i64 p[N],q[N];
int n,a[N];

int main()
{
    int i;
    RD(n);
    FOR1(i,n) RD(a[i]);
    int j,k;
    p[1]=1;
    for(i=2;i<=n;i++)
    {
        q[i]=p[i-1]+1;
        if(a[i]==i) p[i]=q[i]+1;
        else
        {
            if(a[i]==1) p[i]=q[i]+1+p[i-1]+1;
            else p[i]=q[i]+1+p[a[i]]-q[a[i]]+1+p[i-1]-p[a[i]];
        }
        p[i]%=mod;
        q[i]%=mod;

    }
    int ans=p[n]+1;
    ans%=mod;
    if(ans<0) ans+=mod;
    PR(ans);

}

 

C. Curious Array

给出一个数列A,m个操作,每个操作给出L,R,k,对于L<=j<=R,将A[j]加上C(j-L+k,k)。最后输出A。C(n,k)-C(n-1,k)=C(n-1,k-1)。假如有操作L=1,R=5,k=4,那么1到5加上的数字分别为C(4,4),C(5,4),C(6,4),C(7,4),C(8,4),

1
1   1   1   1   1   1
1   2   3   4   5   6
1   3   6  10  15 21
1   4  10 20  35 56
1   5  15 35  70 126

因此设置一个数组f[K][N],将f[k+1][L]加上1即可,最后一层层向上叠加。同时f[i][R+1]将减去某个数以抵消影响。

int C[N][105];

void init()
{
    int i,j;
    C[0][0]=1;
    for(i=1;i<N;i++)
    {
        C[i][0]=1;
        for(j=1;j<=101;j++) C[i][j]=(C[i-1][j]+C[i-1][j-1])%mod;
    }
}

int a[N],f[105][N],n,m;



int main()
{
    init();
    RD(n,m);
    int i,j,k;
    FOR1(i,n) a[i]=getInt();
    while(m--)
    {
        int L,R,k;
        RD(L,R,k);
        (f[k+1][L]+=1)%=mod;
        for(i=1;i<=k+1;i++)
        {
            (f[i][R+1]-=C[R-L+k+1-i][k+1-i])%=mod;
        }
    }
    for(i=100;i>=0;i--)
    {
        k=0;
        for(j=1;j<=n;j++)
        {
            (k+=f[i+1][j])%=mod;
            (f[i][j]+=k)%=mod;
        }
    }
    for(i=1;i<=n;i++)
    {
        (f[0][i]+=a[i])%=mod;
        if(f[0][i]<0) f[0][i]+=mod;
        printf("%d",f[0][i]);
        if(i<n) putchar(' ');
    }
    puts("");

}

 

D. Largest Submatrix 3

给出一个矩阵,找出一个最大的的子矩阵是使得子矩阵内的数字各不相同。用一个map:mp[x][j]表示第j列的数字x上一次出现的行数。用f[a][b]表示当前行的列区间[a,b]向上最大的延伸长度。用(i+1-f[a][b])*(b-a+1)更新答案。

int a[N][N],n,m,f[N][N];
map<int,int> mp[N*N];


int main()
{
    RD(n,m);
    int i,j,k,t;
    FOR0(i,n) FOR0(j,m) RD(a[i][j]);
    int ans=0;
    FOR0(i,n)
    {
        FOR0(j,m)
        {
            map<int,int>::iterator it;
            int x=a[i][j];
            for(it=mp[x].begin();it!=mp[x].end();it++)
            {
                int a=it->first;
                int b=j;
                if(a>b) swap(a,b);
                upMax(f[a][b],it->second);
            }
            mp[x][j]=i+1;
        }
        for(t=1;t<m;t++) for(k=0;k+t<m;k++)
        {
            upMax(f[k][k+t],f[k][k+t-1]);
            upMax(f[k][k+t],f[k+1][k+t]);
        }
        for(t=0;t<m;t++) for(k=t;k<m;k++)
        {
            upMax(ans,(i-f[t][k]+1)*(k-t+1));
        }

    }
    PR(ans);
}

  

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值