6.2三道模拟

真的是太菜了...

题也不会做,策略也失误,对T2过于自信认为自己能A,结果T3看都没看...最后只拿100分

这个题应该拿250+的啊...

T1 https://www.luogu.org/problemnew/show/P4071

预处理组合数和错排直接回答就行

30mins(考试时)

#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
#include<climits>
#include<ctime>
#include<vector>
#include<map>
#include<queue>
using namespace std;
#define ll long long
inline ll read()
{
    ll ans = 0,op = 1;
    char ch = getchar();
    while(ch < '0' || ch >'9')
    {
        if(ch == '-') op = -1;
        ch = getchar();
    }
    while(ch >= '0' && ch <= '9')
    {
        (ans *= 10) += ch - '0';
        ch = getchar();
    }
    return ans * op;
}
const int mod = 1e9 + 7;
const int maxn = 1e6 + 10;
ll power(ll a,ll b)
{
    ll ans = 1,res = a;
    while(b)
    {
        if(b & 1) (ans *= res) %= mod;
        (res *= res) %= mod;
        b >>= 1;
    }
    return ans;
}
ll fac[maxn],inv[maxn];
ll n,m;
ll ans;
ll cal(ll n,ll m)
{
    return fac[n] * inv[m] % mod * inv[n - m] % mod;
}
ll f[maxn];
int main()
{
    ll t = read();
    inv[0] = fac[0] = 1;
    for(int i = 1;i <= maxn - 10;i++)
    {
        fac[i] = fac[i - 1] * i % mod;
        inv[i] = power(fac[i],mod - 2);
    }
    f[1] = 0,f[2] = f[0] = 1;
    for(int i = 3;i <= maxn - 10;i++)
        f[i] = (i - 1) * (f[i - 1] + f[i - 2]) % mod;
    while(t--)
    {
        n = read(),m = read();
        printf("%lld
",cal(n,m) * f[n - m] % mod);
    }
}
View Code

T2 https://www.luogu.org/problemnew/show/P2446

考虑到可以让无数个机器人同时出发,那么一个节点可以有两个dis值

分别是图上的最短路距离和实际到达的最早时间

然后你可以边dij边处理第二个值,当一个节点的所有保护城市都被访问过以后就把这个点塞进堆

爆零是因为更新dis的时候,想当然的按照传统dij用数组里的值更新,然而这道题应该拿实际时间更新,不然一边dij一边处理就失去意义了,还不如用拓扑排序

2.5h(考试 + 订正)

#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
#include<queue>
#include<vector>
using namespace std;
typedef long long ll;
#define O(x) cout << #x << "  " << x << endl;
#define pii pair<ll,int> 
#define mp make_pair
#define B cout << "breakpoint" << endl;
inline int read()
{
    int ans = 0,op = 1;
    char ch = getchar();
    while(ch < '0' || ch > '9')
    {
        if(ch == '-') op = -1;
        ch = getchar();
    }
    while(ch >= '0' && ch <= '9')
    {
        (ans *= 10) += ch - '0';
        ch = getchar();
    }
    return ans * op;
}
const int maxn = 3005;
const int maxm = 70005;
const ll inf = 99999999999;
int n,m;
struct egde
{
    int to,next;
    ll cost;
}e[maxm];
int fir[maxn],alloc;
void adde(int u,int v,ll w)
{
    e[++alloc].next = fir[u];
    fir[u] = alloc;
    e[alloc].to = v;
    e[alloc].cost = w;
}
vector<int> l[maxn];
int cnt[maxn];

ll dis[maxn];
ll res[maxn];
bool vis[maxn];
void dij()
{
    for(int i = 1;i <= n;i++) dis[i] = inf;
    priority_queue<pii,vector<pii>,greater<pii> > p;
    p.push(mp(0,1));
    dis[1] = 0;
    while(p.size())
    {
        pii t = p.top();
        p.pop();
        int u = t.second;
        //O(u);
        ll dist = t.first;
        if(vis[u]) continue;
        vis[u] = 1;
        for(int i = fir[u];i;i = e[i].next)
        {
            int v = e[i].to;
            ll w = e[i].cost;
            if(dis[v] > dist + w)
            {
                dis[v] = dist + w;
                if(cnt[v] == 0) p.push(mp(max(dis[v],res[v]),v));
            }
        }
        for(int i = 0;i < l[u].size();i++)
        {
            int v = l[u][i];
            //O(v);
            cnt[v]--;
            res[v] = max(res[v],dist);
            if(cnt[v] == 0) p.push(mp(max(dis[v],res[v]),v));
        }
    }
}
int main()
{
    //freopen("landcraft.in","r",stdin);
    //freopen("landcraft.out","w",stdout);
    n = read(),m = read();
    for(int i = 1;i <= m;i++)
    {
        int u = read(),v = read(),w;
        scanf("%lld",&w);
        if(u == v) continue;
        adde(u,v,w);
    }
    for(int i = 1;i <= n;i++)
    {
        cnt[i] = read();
        for(int j = 1;j <= cnt[i];j++)
        {
            int v = read();
            l[v].push_back(i);
        }
    }
    dij();
    printf("%lld",max(dis[n],res[n]));
}
View Code

T3 https://www.luogu.org/problemnew/show/P3745

这么直白的题考试的时候应该多放时间的...确实是被T2扰乱视听了

不会三分,用个很直白的枚举做法

枚举最晚结束时间,你就可以算出在这个时间结束的时候的花费

O(nlogn),虽然比别的做法多个log,但是代码难度几乎是没有的,而且非常易懂,重要的是可以过

然后不要忘了,学生的不满意度应该是被加进花费的(根据定义)

1.0h(订正)

#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
#include<climits>
#include<ctime>
#include<vector>
#include<map>
#include<queue>
using namespace std;
typedef int mainint;
#define int unsigned long long
#define O(x) cout << #x << " " << x << endl;
inline int read()
{
    int ans = 0,op = 1;
    char ch = getchar();
    while(ch < '0' || ch >'9')
    {
        if(ch == '-') op = -1;
        ch = getchar();
    }
    while(ch >= '0' && ch <= '9')
    {
        (ans *= 10) += ch - '0';
        ch = getchar();
    }
    return ans * op;
}
const int maxn = 1e5 + 5;
int A,B,C;
int n,m;
int t[maxn],sumt[maxn];//希望时间 
int b[maxn],sumb[maxn];//实际时间 
int ans = LONG_LONG_MAX;
mainint main()
{
    A = read(),B = read(),C = read();
    n = read(),m = read();
    for(int i = 1;i <= n;i++) t[i] = read();
    for(int i = 1;i <= m;i++) b[i] = read();
    sort(t + 1,t + 1 + n);
    sort(b + 1,b + 1 + m);
    for(int i = 1;i <= n;i++)  sumt[i] = sumt[i - 1] + t[i];
    for(int i = 1;i <= m;i++)  sumb[i] = sumb[i - 1] + b[i];
    for(int i = min(t[1],b[1]);i <= max(t[n],b[m]);i++)
    {
        int tp = 0;
        int p1 = lower_bound(b + 1,b + 1 + m,i) - b;//b[p1] <= i的最大b[p1]
        while(b[p1] > i) p1--;
        int tp1 = p1 * i - sumb[p1],tp2 = sumb[m] - sumb[p1] - (m - p1) * i;//tp1:可以调的时间,tp2:实际需要调的时间 
        //O(i); O(tp1); O(tp2);
        if(A < B)
        {
            if(tp1 > tp2) tp += A * tp2;
            else tp += A * tp1 + B * (tp2 - tp1);
        }
        else tp += B * tp2;
        int tot = lower_bound(t + 1,t + 1 + n,i) - t;
        while(t[tot] > i) tot--;//t[tot] <= i 的最大t[tot]
        tp = tp + (tot * i - sumt[tot]) * C;
        ans = min(ans,tp);
    }
    cout << ans;
}
        
    
View Code
原文地址:https://www.cnblogs.com/LM-LBG/p/10983694.html