PRank3

  • 窝太水了..
  • 搞不动了- -

A Quicksum

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;

const int MAX = 512;
char buffer[MAX];

int main()
{
    int len;
    while (fgets(buffer, MAX, stdin) != NULL)
    {
        //printf("read %s\n", buffer);
        if (buffer[0] == '#')
        {
            break;
        }
        len = strlen(buffer);

        int sum = 0;
        for (int i = 0; i + 1 < len; ++i)
        {
            sum += (buffer[i] == ' ' ? 0 : buffer[i] - 'A' + 1) * (i + 1);
        }
        printf("%d\n", sum);
    }
    return 0;
}

B Asteroids

  • 二分图最大匹配
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;

const int MAX = 512;
int G[MAX][MAX];
int match[MAX];
bool vis[MAX];
int n, k;

int dfs(int v)
{
    int t;
    for (int i = 1; i <= n; ++i)
    {
        if (G[i][v] && !vis[i])
        {
            vis[i] = true;
            t = match[i];
            match[i] = v;
            if (t == -1 || dfs(t))
            {
                return 1;
            }
            match[i] = t;
        }
    }
    return 0;
}

int main()
{
    while (~scanf(" %d %d", &n, &k))
    {
        memset(G, 0, sizeof(G));
        int x, y;
        for (int i = 0; i < k; ++i)
        {
            scanf(" %d %d", &x, &y);
            G[x][y] = 1;
        }

        int ans = 0;
        memset(match, -1, sizeof(match));
        for (int i = 1; i <= n; ++i)
        {
            memset(vis, false, sizeof(vis));
            ans += dfs(i);
        }
        printf("%d\n", ans);
    }
    return 0;
}

C NastyHacks

#include <cstdio>
#include <cstring>

int main()
{
    int T;
    scanf(" %d", &T);
    while (T--)
    {
        int r, e, c;
        scanf(" %d %d %d", &r, &e, &c);
        if (e - c == r)
        {
            puts("does not matter");
        }
        else if (e - c > r)
        {
            puts("advertise");
        }
        else
        {
            puts("do not advertise");
        }
    }

    return 0;
}

F ScoutYYFI

  • operator 时忘了写返回语句…
  • 早知道开-Wall了…
  • 妈蛋p.p
    / \
    / \
    /  \
  • 首先
    dp[n]=dp[n1]p+dp[n2](1p)
  • 然后我们知道,炸弹将道路分成了若干段,设炸弹位置为 pos[i] ,我们要做的就是分段考虑 pos[j]pos[j+1] ,当然了,第一段是 1pos[0] 额外算
  • 在每一段 [a,b] 上存活的概率都是
    dp[b1](1p)
  • 各段相乘即可。对某一段,用矩阵快速幂加速。
#include <cstdio>
#include <cstring>
#include <cmath>
#include <vector>
#include <algorithm>
using namespace std;

typedef long long ll;
struct Mat
{
    double a[2][2];
    Mat operator*(const Mat& B)const
    {
        Mat res;
        for (int i = 0; i < 2; ++i)
        {
            for (int j = 0; j < 2; ++j)
            {
                res.a[i][j] = 0.0;
                for (int k = 0; k < 2; ++k)
                {
                    res.a[i][j] += a[i][k] * B.a[k][j];
                }
            }
        }
        return res;
    }
    void print()
    {
        for (int i = 0; i < 2; ++i)
        {
            for (int j = 0; j < 2; ++j)
            {
                printf("%.2f ", a[i][j]);
            }
            puts("");
        }
    }
};

Mat fast_pow(Mat A, ll n)
{
    Mat res;
    res.a[0][0] = res.a[1][1] = 1.0;
    res.a[0][1] = res.a[1][0] = 0.0;
    while (n > 0)
    {
        if (n & 1)
        {
            res = res * A;
        }
        A = A * A;
        //res.print();
        //A.print();
        //printf("n = %lld\n", n);
        //puts("---------");
        n >>= 1;
    }
    return res;
}

int n;
double p;

double gao(ll from, ll to)
{
    ll n = to - from + 1;
    if (n == 1)
    {
        return 1.0;
    }
    else if (n <= 0)
    {
        return 0.0;
    }
    Mat mm;
    mm.a[0][0] = p;
    mm.a[0][1] = 1.0;
    mm.a[1][0] = 1.0 - p;
    mm.a[1][1] = 0.0;

    Mat A;
    A.a[0][0] = 1.0;
    A.a[0][1] = 0.0;
    A.a[1][0] = 1.0;
    A.a[1][1] = 1.0;

    A = A * (fast_pow(mm, n - 1));
    return A.a[0][0];
}

int main()
{
    vector<ll> pos;
    while (~scanf(" %d %lf", &n, &p))
    {
        pos.clear();
        ll pp;
        for (int i = 0; i < n; ++i)
        {
            scanf(" %lld", &pp);
            pos.push_back(pp);
        }
        sort(pos.begin(), pos.end());
        if (pos[0] == 1)
        {
            puts("0.0000000");
            continue;
        }
        ll left = 1;
        double ans = 1.0;
        for (int i = 0; i < n; ++i)
        {
            ans *= gao(left, pos[i] - 1);
            ans *= 1.0 - p;
            left = pos[i] + 1;
        }
        printf("%.7f\n", ans);
    }
    return 0;
}

D HardLife

  • 这啥?不知道
  • 是最大密度子图
  • 模板
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<algorithm>
using namespace std;
const int N=400,M=5000;
const double inf=1e10,eps=1e-6;
int head[N],nc,du[N];
struct data
{
    int x,y;
}po[M];
struct edge
{
    int x,y,next;
    double cap;
} edge[M*3];
void add(int x,int y,double cap)
{
    edge[nc].x=x;
    edge[nc].y=y;
    edge[nc].cap=cap;
    edge[nc].next=head[x];
    head[x]=nc++;
    edge[nc].x=y;
    edge[nc].y=x;
    edge[nc].cap=0;
    edge[nc].next=head[y];
    head[y]=nc++;
}
int num[N],h[N],S,T,n,m;
double findpath(int x,double flow)
{
    if(x==T)
        return flow;
    double res=flow;
    int pos=n-1;
    for(int i=head[x]; i!=-1; i=edge[i].next)
    {
        int y=edge[i].y;
        if(h[x]==h[y]+1&&edge[i].cap>eps)
        {
            double
                tp=findpath(y,min(edge[i].cap,res));
            res-=tp;
            edge[i].cap-=tp;
            edge[i^1].cap+=tp;
            if(res<eps||h[S]==n)
                return flow-res;
        }
        if(edge[i].cap>eps&&h[y]<pos)
            pos=h[y];
    }
    if(abs(res-flow)<eps)
    {
        num[h[x]]--;
        if(num[h[x]]==0)
        {
            h[S]=n;
            return flow-res;
        }
        h[x]=pos+1;
        num[h[x]]++;
    }
    return flow-res;
}
double Sap(double x)
{
    memset(head,-1,sizeof(head));
    nc=0;
    for(int i=0;i<m;i++)
    {
        add(po[i].x,po[i].y,1.0);
        add(po[i].y,po[i].x,1.0);
    }
    for(int i=1;i<T;i++)
    {
        add(S,i,(double)m);
        add(i,T,(double)m+2*x-(double)du[i]);
    }
    double ans=0;
    memset(h,0,sizeof(h));
    memset(num,0,sizeof(num));
    while(h[S]!=n)
        ans+=findpath(S,(T-1)*m);
    return (T-1.0)*m-ans;
}
bool vis[N];
int dfs(int now)
{
    int cnt=1;
    vis[now]=true;
    for(int i=head[now];i!=-1;i=edge[i].next)
    {
        if(!vis[edge[i].y]&&edge[i].cap>eps)
        {
            cnt+=dfs(edge[i].y);
        }
    }
    return cnt;
}
int main()
{
    while(scanf("%d%d",&n,&m)!=EOF)
    {
        memset(du,0,sizeof(du));
        S=0;T=n+1;n=T+1;
        for(int i=0; i<m; i++)
        {
            scanf("%d%d",&po[i].x,&po[i].y);
            du[po[i].x]++;du[po[i].y]++;
        }
        if(m==0)
        {
            printf("1\n1\n");
            continue;
        }
        double ll=0,rr=(double)m,mid;
        while(rr-ll>1.0/(T-1.0)/(T-1.0))
        {
            mid=(ll+rr)/2.0;
            double tp=Sap(mid);
            if(abs(tp)<eps)
                rr=mid;
            else
                ll=mid;
        }
        memset(vis,false,sizeof(vis));
        int ans=dfs(S)-1;
        if(ans==0)
        {
            Sap(ll);
            memset(vis,false,sizeof(vis));
            ans=dfs(S)-1;
        }
        printf("%d\n",ans);
        for(int i=1;i<T;i++)
            if(vis[i])
                printf("%d\n",i);
    }
    return 0;
}

H Push Botton Lock

  • 显然,我们先从 B 个里面取i个,然后把 i 个分到j个集合,同时把这 j 个集合排顺序即可。那么就是
    ans[B]=i=1B(iB)j=1i(dp[i][j]j!)
  • 其中, (iB) 表示从 B 个里取i个, dp[i][j] 表示把 i 个不同元素放入j个集合中的方案数, j! 是对 j 个集合的排序
  • 注意有
    (iB)=(iB1)+(i1B)

    以及
    dp[i][j]=dp[i1][j1]+jdp[i1][j]
    处理 i 个元素时,我们考虑第i个元素应该怎么放,一种方法是单独占一个集合,于是前 i1 个需要放入 j1 个集合,即为 dp[i1][j1] ;另一种是不单独放,也就是前 i1 个占用全部 j 个集合,然后第i个只需要从这 j 个集合选一个放入即可。便是上述dp[i][j]=dp[i1][j1]+jdp[i1][j]
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;

typedef long long ll;
const int MAX = 12;
ll dp[MAX][MAX]; //dp[i][j] = j * dp[i - 1][j] + dp[i - 1][j - 1]
ll C[MAX][MAX]; //c(i,j)
ll fac[MAX] = {1LL};

int main()
{
    for (int i = 1; i < MAX; ++i)
    {
        fac[i] = fac[i - 1] * i;
    }
    dp[1][1] = 1LL;
    for (int j = 1; j < MAX; ++j)
    {
        for (int i = 2; i < MAX; ++i)
        {
            dp[i][j] = j * dp[i - 1][j] + dp[i - 1][j - 1];
        }
    }

    C[1][0] = C[1][1] = 1;
    for (int i = 2; i < MAX; ++i)
    {
        C[i][0] = 1;
        for (int j = 1; j < MAX; ++j)
        {
            C[i][j] = C[i - 1][j] + C[i - 1][j - 1];
        }
    }

    int T, B;
    scanf(" %d", &T);
    while (T--)
    {
        scanf(" %d", &B);
        ll ans = 0LL;
        for (int i = 1; i <= B; ++i)
        {
            for (int j = 1; j <= i; ++j)
            {
                ans += C[B][i] * (dp[i][j] * fac[j]);
            }
        }
        static int cas = 1;
        printf("%d %d %lld\n", cas++, B, ans);
    }
    return 0;
}

一把辛酸泪

  • 孩子,加油…
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值