牛客练习赛20

A.礼物

题意:有n种1元礼物和m种2元礼物 你有k元你能搭配出多少种组合

题解:他们都写的背包 发现我不会

   就枚举买几个1元的礼物 剩下部分买2元的 然后用组合数学搞搞

#include 
#include 
#include 
using namespace std;
typedef long long ll;

ll f[2005][2005];
void fun(ll mod)
{
    for(int i = 0; i <= 2000; i++) f[i][0] = 1LL;
    for(int i = 1; i <= 2000; i++)
    {
        for(int j = 1; j <= i; j++)
            f[i][j] = (f[i - 1][j - 1] + f[i - 1][j]) % mod;
    }
}

int main()
{
    int T;
    scanf("%d", &T);
    while(T--)
    {
        ll n, m, k, p;
        cin>>n>>m>>k>>p;
        fun(p);

        ll ans = f[k + n - 1][k];
        if(m != 0)
        {
            for(int i = 1; i < k; i++)
            {
                if((k - i) & 1) continue;
                int j = (k - i) >> 1;
                ans = (ans + f[i + n - 1][i] * f[j + m - 1][j] % p) % p;
            }
        }
        if(k % 2 == 0) ans = (ans + f[k / 2 + m - 1][k / 2]) % p;

        printf("%lld\n", ans);
    }
    return 0;
}
View Code

 

B.麻婆豆腐

题意:给出n枚硬币正面朝上的概率 求有多少子集使得硬币正面朝上次数为奇数的概率等于偶数

题解:发现对于一个集合 如果有正面朝上概率为0.5的硬币 那么其余硬币随便怎么搞都满足

   比如我们要求正面朝上的概率为奇数的个数 假设除了0.5的硬币其他硬币为奇数的概率为p 为偶数的概率为1-p

   那么p为奇数 = p*0.5 + (1 - p)*0.5 所以含有0.5正面朝上概率硬币的子集一定满足

#include 
#include 
#include 
#include 
using namespace std;
typedef long long ll;

int main()
{
    int T;
    scanf("%d", &T);
    while(T--)
    {
        int cnt = 0;
        int n; cin>>n;
        double x;
        for(int i = 1; i <= n; i++)
        {
            cin>>x;
            if(fabs(x - 0.5) < 1e-7) cnt++;
        }
        ll ans = ((1LL << (ll)cnt) - 1LL) * (1LL << (ll)(n - cnt));
        printf("%lld\n", ans);
    }
    return 0;
}
View Code

 

C.寻宝

题意:n个点 每个点能到达另外一个点 选择一个点作为起点 能最多经历多少不同的点

题解:n个点n条边 那么这一定是由一些带环树组成的 dfs找出每一块然后记忆化更新答案

#include 
#include 
#include 
#include 
using namespace std;
const int maxn = (1 << 24) + 5;
typedef long long ll;

vector<int> g;
int to[maxn];
int dp[maxn];
int vis[maxn];

int st;
void dfs(int x)
{
    dp[x] = 1;
    vis[x] = -1;
    int v = to[x];
    if(v == x)
    {
        vis[x] = 1;
        return;
    }

    if(vis[v] == 1) dp[x] += dp[v];
    else if(vis[v] == 0)
    {
        dfs(v);
        if(st == -1) dp[x] += dp[v];
        else if(x == st)
        {
            g.push_back(x);
            int tmp = g.size();
            for(int i = 0; i < g.size(); i++) dp[g[i]] = tmp;
            st = -1;
            g.clear();
        }
        else g.push_back(x);
    }
    else if(vis[v] == -1) st = v, g.push_back(x);
    vis[x] = 1;
}

int main()
{
    int T;
    scanf("%d", &T);
    while(T--)
    {
        st = -1;
        ll a, b, c, n;
        cin>>a>>b>>c>>n;

        for(ll i = 0; i < n; i++)
        {
            dp[i] = 0; vis[i] = 0;
            to[i] = (a * i * i  + b * i + c) % n;
            to[i] = (to[i] + n) % n;
        }
        int ans = 0;
        for(int i = 0; i < n; i++)
        {
            if(!vis[i]) dfs(i);
            ans = max(ans, dp[i]);
        }
        printf("%d\n", ans);
    }
    return 0;
}
View Code

 

D.最短路2

题意:在网格图上给两个点和一条直线 能从网格和直线上走 求最短路

题解:以两个点做出一个正方形 然后这条直线最多会和这个正方形有两个交点 以这些点建图跑最短路就好了

   直线上两个点之间的距离是普通距离 其他则是曼哈顿距离

#include 
#include 
#include 
using namespace std;

double x1, yy, x2, y2, a, b, c;

struct node
{
    double x, y;
    int ty;
}E[25];

struct no1
{
    int to;
    double val;
};
vector g[35];

double dis[35];
int vis[25];
queue<int> que;

void spfa()
{
    for(int i = 1; i <= 10; i++) dis[i] = 1000000005;
    memset(vis, 0, sizeof(vis));
    dis[1] = 0; vis[1] = 1;
    while(!que.empty()) que.pop();
    que.push(1);

    while(!que.empty())
    {
        int u = que.front();
        que.pop();
        vis[u] = 0;
        for(int i = 0; i < g[u].size(); i++)
        {
            if(dis[u] + g[u][i].val < dis[g[u][i].to])
            {
                dis[g[u][i].to] = dis[u] + g[u][i].val;
                if(!vis[g[u][i].to])
                {
                    vis[g[u][i].to] = 1;
                    que.push(g[u][i].to);
                }
            }
        }
    }
}

int main()
{
    int T;
    scanf("%d", &T);
    while(T--)
    {
        for(int i = 1; i <= 20; i++) g[i].clear();
        scanf("%lf %lf %lf %lf %lf %lf %lf", &x1, &yy, &x2, &y2, &a, &b, &c);
        double xx = min(x1, x2);
        double xd = max(x1, x2);
        double yx = min(yy, y2);
        double yd = max(yy, y2);
        E[1].x = x1; E[1].y = yy; E[1].ty = 0;
        E[2].x = x2; E[2].y = y2; E[2].ty = 0;
        E[3].x = x1; E[3].y = y2; E[3].ty = 0;
        E[4].x = x2; E[4].y = yy; E[4].ty = 0;
        int cnt = 4;


        if(fabs(a) > 1e-9)
        {
            double x3 = (c - b * yy) / a;
            if(x3 >= xx && x3 <= xd)
            {
                cnt++;
                E[cnt].x = x3; E[cnt].y = yy; E[cnt].ty = 1;
            }

            double x4 = (c - b * y2) / a;
            if(x4 >= xx && x4 <= xd)
            {
                cnt++;
                E[cnt].x = x4; E[cnt].y = y2; E[cnt].ty = 1;
            }
        }

        if(fabs(b) > 1e-9)
        {
            double y3 = (c - a * x1) / b;
            if(y3 >= yx && y3 <= yd)
            {
                cnt++;
                E[cnt].x = x1; E[cnt].y = y3; E[cnt].ty = 1;
            }

            double y4 = (c - a * x2) / b;
            if(y4 >= yx && y4 <= yd)
            {
                cnt++;
                E[cnt].x = x2; E[cnt].y = y4; E[cnt].ty = 1;
            }
        }

        for(int i = 1; i <= cnt; i++)
        {
            for(int j = 1; j <= cnt; j++)
            {
                if(i == j) continue;
                if(E[i].ty + E[j].ty < 2)
                {
                    no1 p; p.to = j; p.val = fabs(E[i].x - E[j].x) + fabs(E[i].y - E[j].y);
                    g[i].push_back(p);
                }
                else if(E[i].ty + E[j].ty == 2)
                {
                    no1 p; p.to = j; p.val = sqrt((E[i].x - E[j].x) * (E[i].x - E[j].x) + (E[i].y - E[j].y) * (E[i].y - E[j].y));
                    g[i].push_back(p);
                }
            }
        }
        spfa();
        printf("%.3lf\n", dis[2]);
    }
    return 0;
}
View Code

 

E.托米历险记 签到

#include 
#include 
#include 
using namespace std;
int sum[5];

int main()
{
    bool f = true;
    int n;
    scanf("%d", &n);
    for(int i = 1; i <= n; i++)
    {
        int x; scanf("%d", &x);
        x /= 25;
        if(x == 1) sum[1]++;
        else if(x == 2)
        {
            if(!sum[1]) f = false;
            sum[1]--;
            sum[2]++;
        }
        else if(x == 4)
        {
            if(sum[1] && sum[2])
            {
                sum[1]--;
                sum[2]--;
            }
            else if(!sum[2])
            {
                sum[1] -= 3;
                if(sum[1] < 0) f = false;
            }
            else if(!sum[1]) f = false;
        }
    }
    if(f) puts("YES");
    else puts("NO");

    return 0;
}
View Code

 

F.填数字 随便贪心

#include 
#include 
#include 
using namespace std;
int a[15];

int main()
{
    int n; cin>>n;

    int zd = 10000000; int mark = -1;
    for(int i = 1; i <= 9; i++)
    {
        cin>>a[i];
        if(a[i] <= zd)
        {
            zd = a[i];
            mark = i;
        }
    }
    zd = n / a[mark];

    if(zd == 0) puts("-1");
    else
    {
        int x = zd * a[mark];
        int res = n - x;
        int cnt = 0;

        for(int i = 9; i > mark; i--)
        {
            while(res >= a[i] - a[mark])
            {
                res -= a[i] - a[mark];
                cnt++;
                printf("%d", i);
            }
        }
        for(int i = cnt + 1; i <= zd; i++) printf("%d", mark);
        puts("");
    }
    return 0;
}
View Code

 

转载于:https://www.cnblogs.com/lwqq3/p/9191700.html

你可能感兴趣的:(数据结构与算法)