Codeforces #277.5

D. 题目要找如题目所示的那种菱形的个数

只要DFS两层,看每个点走两步都可以到哪些点,记录下来,最后就是组合数统计一下和就行了。

#include <stdio.h>
#include <string.h>
#include <algorithm>
#include <vector>
using namespace std;

vector<int> edge[3005];
int ans[3005][3005];

void dfs(int t,int s,int step)
{
    int i;
    if (step==2)
    {
        ans[s][t]++;
        return;
    }
    for (i=0;i<edge[t].size();i++)
    {
        dfs(edge[t][i],s,step+1);
    }
}

int main()
{
    int i,j,n,m,x,y;
    scanf("%d%d",&n,&m);
    for (i=0;i<m;i++)
    {
        scanf("%d%d",&x,&y);
        edge[x].push_back(y);
    }
    for (i=1;i<=n;i++)
    {
        dfs(i,i,0);
    }
    long long s=0;
    for (i=1;i<=n;i++)
    {
        for (j=1;j<=n;j++)
        {
            if (i==j) continue;
            s+=(ans[i][j]*(ans[i][j]-1))/2;
        }
    }
    printf("%I64d\n",s);
    return 0;
}

E. 最优比例的问题

题目要求的是(d1+d2+d3+....)/(b1+b2+b3+....)的比例最小,假设(d1+d2+...)/(b1+b2+b3+...)的最小值为r,则有(d1+d2+...)/(b1+b2+...)>=r

整理一下得到(d1-b1*r)+(d2-b2*r)+...>=0

所以可以二分r,然后O(n^2)计算左边部分的最小值,看是否大于0,如果大于0,则扩大r,否则缩小r。

代码

#include <stdio.h>
#include <math.h>
#include <string.h>
#include <algorithm>
using namespace std;

#define eps 1e-9

int x[1005];
int b[1005];
double dp[1005];
int before[1005];
int n,l;

bool checkValid(double r)
{
    int i,j;
    for (i=0;i<=n;i++) dp[i]=1e12;
    dp[0]=0;
    for (i=1;i<=n;i++)
    {
        for (j=0;j<i;j++)
        {
            double tmp=dp[j]+sqrt(abs(l-(x[i]-x[j]))*1.0)-r*b[i];
            if (tmp<dp[i])
            {
                dp[i]=tmp;
                before[i]=j;
            }
        }
    }
    return dp[n]>0;
}

void printAns(int t)
{
    if (t==0) return;
    printAns(before[t]);
    printf("%d",t);
    if (t<n) printf(" ");
}

int main()
{
    int i,j;
    scanf("%d%d",&n,&l);
    x[0]=b[0]=0;
    for (i=1;i<=n;i++)
    {
        scanf("%d%d",&x[i],&b[i]);
    }
    double l=0,r=1e7;
    while((r-l)>eps)
    {
        double mid=(l+r)/2;
        if (checkValid(mid)) l=mid;
        else r=mid;
    }
    printAns(n);
    return 0;
}

F. 简单dp,dp[i][j]表示还剩下i列没有1,j列只有一个1的方法数,然后三种转移方式:找两列没有1的都加上1,找一列没有1,一列只有一个1的加上1,还有找两列只有一个1的,都加上1,最后dp[0][0]就是答案。

代码

#include <stdio.h>
#include <string.h>
#include <algorithm>
using namespace std;

char str[1000];
int init[1000];
long long dp[505][505];

int main()
{
    int i,j,n,m,mod;
    scanf("%d%d%d",&n,&m,&mod);
    memset(init,0,sizeof(init));
    for (i=0;i<m;i++)
    {
        scanf("%s",str);
        for (j=0;j<n;j++)
        {
            if (str[j]=='1') init[j]++;
        }
    }
    int zero=0,one=0;
    for (i=0;i<n;i++)
    {
        if (init[i]==0) zero++;
        else if (init[i]==1) one++;
    }
    memset(dp,0,sizeof(dp));
    dp[zero][one]=1;
    for (i=zero;i>=0;i--)
    {
        for (j=n;j>=0;j--)
        {
            if (i>=2) dp[i-2][j+2]+=(long long)i*(i-1)/2*dp[i][j]%mod;
            if (i>=1 && j>=1) dp[i-1][j]+=(long long)i*j*dp[i][j]%mod;
            if (j>=2) dp[i][j-2]+=(long long)j*(j-1)/2*dp[i][j]%mod;
        }
    }
    printf("%I64d\n",dp[0][0]);
    return 0;
}


你可能感兴趣的:(Codeforces #277.5)