10.1 Morning


Problem A. calculator

【题目描述】

现在你手里有一个计算器,上面显示了一个数S。这个计算器非常奇怪,它只有两个按钮,分别可以把屏幕上显示的数值加上1或者减去1。并且,如果计算器屏幕上的数变成了负数,那么计算器就会损坏。现在你想要在K次操作之内把屏幕上的数字变成T,而且不让计算器损坏,求一个有多少种方案。 对10^9+7取模。

两种方案不同当且仅当按钮被按下的序列不同。

【输入描述】

一行三个整数S,T,K

【输出描述】

一行一个正整数,表示答案

【输入输出样例】

【input】

0 1 3

【output】

3

【样例解释】

一共有3种可能的操作序列

+1;

+1,-1,+1;

+1,+1,-1

【数据范围】

对于30%的数据,S,T,K<=10

对于60%的数据,S,T,K<=1000

对于100%的数据,0<=S,T,K<=100000


【题解】

10.1清北刷题记-LMLPHP

10.1清北刷题记-LMLPHP

10.1清北刷题记-LMLPHP


【代码实现】

30分代码(考场代码)

#include<cstdio>
#define mod 1000000007
long long s,t,k,ans;
void dfs(long long pos,long long tot)
{
    if(pos==t) ans=(ans+1)%mod;
    if(tot>=k) return;
    dfs(pos+1,tot+1);
    if(pos>0) dfs(pos-1,tot+1);
}
int main()
{
    freopen("calculator.in","r",stdin);
    freopen("calculator.out","w",stdout);
    scanf("%lld%lld%lld",&s,&t,&k);
    dfs(s,0);
    printf("%lld",ans%mod);
    fclose(stdin);
    fclose(stdout);
    return 0;
}

60分代码(!wyxdrqc大佬的代码)

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cctype>
#include<cmath>
#include<algorithm>
using namespace std;
typedef long long LL;
const LL mod = 1e9 + 7;
const int N = 4e3 + 4;
LL f[N][N];
LL s,t,k;
inline LL dfs(LL now,LL last){
    if(abs(now - t) > k - last) return 0;
    if(now < 0) return 0;
    if(f[now][last]) return f[now][last];
    if(now != t)
    f[now][last] = (dfs(now + 1,last + 1)  + dfs(now - 1,last + 1))%mod;
    else f[now][last] = (dfs(now + 1,last + 1)  + dfs(now - 1,last + 1) + 1)%mod;
    return f[now][last];
}
int main(){
    freopen("calculator.in","r",stdin);
    freopen("calculator.out","w",stdout);
    cin >> s >> t >> k;
    f[t][k] = 1;
    cout << dfs(s,0) << endl;
    return 0;
}

100分代码(std)

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

const int N = (int)2e5, mod = (int)1e9 + 7;
typedef long long ll;

int S, T, K;
int fac[N + 10], ifac[N + 10];

int pow(int x, int y) {
    ll t = x, r = 1;
    for ( ; y; y >>= 1, t = t * t % mod)
        if (y & 1) r = r * t % mod;
    return r;
}

void preprocessing() {
    fac[0] = 1;
    for (int i = 1; i <= N; ++i) fac[i] = (ll)fac[i - 1] * (ll)i % mod;
    ifac[N] = pow(fac[N], mod - 2);
    for (int i = N - 1; i >= 0; --i) ifac[i] = (ll)ifac[i + 1] * (ll)(i + 1) % mod;
}

int c(int n, int r) {
    return (ll)fac[n] * (ll)ifac[r] % mod * (ll)ifac[n - r] % mod;
}

int main() {
    freopen("calculator.in", "r", stdin);
    freopen("calculator.out", "w", stdout);

    preprocessing();
    scanf("%d %d %d", &S, &T, &K);
    if (S > T) swap(S, T);

    int ans = 0;
    for (int i = 0; i <= K; ++i) {
        if ((i + T - S) & 1) continu
        int x = (i - T + S) >> 1, y = (i + T - S) >> 1;
        if (x < 0) continue;
        (ans += c(x + y, x)) %= mod;
        if (x > S) (ans += (mod - c(x + y, x - S - 1))) %= mod;
    }

    printf("%d\n", ans);
    return 0;
}

Problem B. work

【题目描述】

有一个工厂一共有m台排成一排的机器,其中第台机器的工作效率是e[i]。

机器有开或者关两种状态,显然当所有机器都开着的时候工作效率可以达到最大。但是由于工厂的供电系统岀现了故障,不能够同时开启仼意连续k+1台机器,否则工厂就会爆炸。

求工厂在不发生爆炸的前提下能够达到的最大效率。

【输入描述】

第一行两个正整数n和k。

接下来n行,每一行一个正整数,代表e[i]。

【输出描述】

一行一个数表示答案。

【输入输出样例】

【input】

5 2

1 2 3 4 5

【output】

12

【数据范围】

对于30%的数据,1<=n<=100

对于100%的数据,1<=n<=100000,1<=k,0<=e[i]<=10^9


【题解】

10.1清北刷题记-LMLPHP


【代码实现】

30分代码

#include<iostream>
#include<cstdio>
using namespace std;
int a[101];
long long f[101][101];
int main ()
{
    freopen("work.in","r",stdin);
    freopen("work.out","w",stdout);
    int n,k,i,j;
    scanf("%d%d",&n,&k);
    for(i=1;i<=n;++i) scanf("%d",&a[i]);
    f[1][1]=a[1];f[1][0]=0;
    for(i=2;i<=n;++i)
      f[1][i]=-1;
    for(i=2;i<=n;++i)
    {
        for(j=1;j<=k;++j)
          if(f[i-1][j]>f[i][0]) f[i][0]=f[i-1][j];
        for(j=1;j<=k;++j)
        {
          if(f[i-1][j-1]!=-1) f[i][j]=f[i-1][j-1]+a[i];
          else f[i][j]=-1;
        }
    }
    long long sum=0;
    for(i=1;i<=k;++i)
      if(f[n][i]>sum) sum=f[n][i];
    cout<<sum<<endl;
    fclose(stdin);fclose(stdout);
    return 0;
}

100分代码

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

typedef long long ll;

const int N = (int)1e5;
typedef long long ll;
typedef int arr[N + 10];

int n, K, f, r;
arr q;
ll e[N + 10], dp[N + 10];

int main() {
    freopen("work.in", "r", stdin);
    freopen("work.out", "w", stdout);

    scanf("%d %d", &n, &K);
    for (int i = 1; i <= n; ++i) scanf("%lld", e + i), e[i] += e[i - 1];

    q[f = r = 1] = 0, dp[0] = 0;

    for (int i = 1; i <= n + 1; ++i) {
        if (q[f] < i - K - 1) ++f;
        dp[i] = dp[q[f]] + e[i - 1] - e[q[f]];
        for ( ; r >= f && dp[q[r]] - e[q[r]] <= dp[i] - e[i]; --r);
        q[++r] = i;
    }

    cout << dp[n + 1] << endl;
    return 0;
}

Problem C. cubes

【题目描述】

约翰和贝西在叠积木。共有30000块积木,编号为1到30000。一开始,这些积木放在地上,自然地分成N堆。贝西接受约翰的指示,把一些积木叠在另一些积木的上面。一旦两块积木相叠, 彼此就再也不会分开了,所以最后叠在一起的积木会越来越高。约翰让贝西依次执行P条操作,操作分为两种:

第一种是移动操作,格式为“移动X到Y的上面”。X和Y代表两块积木的编号,意思是将X所的那堆积木,整体叠放到Y所在的那堆积木之上;

第二种是统计操作,格式为“统计Z下方的积木数量”。Z代表一块积木的编号,意思是贝西需要报告在编号为Z的积木之下还有多少块积木

请编写一个程序,帮助贝西回答每条统计问题。

【输入格式】

第一行:单个整数:P,1 ≤ P ≤ 10^5

第二行到第P + 1行:每行描述一条命令,如果这行开头的字母是 M,代表一条移动命令,后面的两个整数代表上文中的X和Y;如果开头字母是 C,代表一条统计命令。后面的整数代表上文中的Z,保证所有的移动命令都有意义,X和Y不会已经出现在同一堆积木里

【输出格式】

对每一个统计命令,输出正确回答,用换行符分开每个查询的结果

【输入输出样例】

【input】

6

M 1 6

C 1

M 2 4

M 2 6

C 3

C 4

【output】

1

0

2

【数据范围】

对于40%的数据,m<=200

对于100%的数据,m<=100000


【题解】

10.1清北刷题记-LMLPHP

 


【代码实现】

40分暴力

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<map>

#define RI register int
using namespace std;
typedef long long ll;

#define max(a,b) ((a) > (b) ? (a) : (b))
#define min(a,b) ((a) < (b) ? (a) : (b))

const int INF = 1e9 + 7;
const int MAXN = 100000 + 5;

inline void read(int &x)
{
    x = 0;
    bool flag = 0;
    char ch = getchar();
    while(ch < '0' || ch > '9')
    {
        if(ch == '-')   flag = 1;
        ch = getchar();
    }
    while(ch >= '0' && ch <= '9')
    {
        x = x * 10 + ch - '0';
        ch = getchar();
    }
    if(flag)    x *= -1;
}

char s[5];
int m,a,b,tot = 0,ans;
map <int,bool>  use;
map <int,int>   num;
int son[MAXN],fa[MAXN],tmp;

int find(int a)
{
    while(son[a] != -1)
        a = son[a];
    return a;
}

int findf(int a)
{
    while(fa[a] != -1)
        a = fa[a];
    return a;
}

int main()
{
    freopen("cubes.in","r",stdin);
    freopen("cubes.out","w",stdout);
    read(m);
    for(int i = 1;i <= m;i ++)
    {
        scanf("%s",s + 1);
        if(s[1] == 'M')
        {
            read(a),read(b);
            if(!use[a])
            {
                num[a] = ++ tot;
                use[a] = 1;son[tot] = -1,fa[tot] = -1;
            }
            if(!use[b])
            {
                num[b] = ++ tot;
                use[b] = 1;son[tot] = -1,fa[tot] = -1;
            }
            if(findf(num[a]) == findf(num[b]))  continue;
            a = find(num[a]),b = findf(num[b]);
            son[a] = b;fa[b] = a;
        }
        else
        {
            read(a);
            if(!use[a])
            {
                num[a] = ++ tot;
                use[a] = 1;son[tot] = -1;
            }
            ans = 0,tmp = num[a];
            while(son[tmp] != -1)
            {
                tmp = son[tmp];
                ans ++;
            }
            cout << ans << endl;
        }
    }
    fclose(stdin);
    fclose(stdout);
    return 0;
}

100分正解

#include <bits/stdc++.h>
using namespace std;

const int N = (int)3e4;
typedef int arr[N + 10];
typedef long long ll;

int m, j, k;
arr ufs, below, sz;
char ope[3];

int find(int x) {
    if (x == ufs[x]) return x;
    int f = find(ufs[x]);
    below[x] += below[ufs[x]];
    return ufs[x] = f;
}

void move(int x, int y) {
    int fx = find(x), fy = find(y);
    ufs[fx] = fy;
    below[fx] += sz[fy];
    sz[fy] += sz[fx];
}

int main() {
    freopen("cubes.in", "r", stdin);
    freopen("cubes.out", "w", stdout);

    for (int i = 1; i <= N; ++i) ufs[i] = i, sz[i] = 1, below[i] = 0;

    for (scanf("%d", &m); m--; ) {
        scanf("%s", ope + 1);
        if (ope[1] == 'M') {
            scanf("%d %d", &j, &k), move(j, k);
        }
        else {
            scanf("%d", &k);
            ufs[k] = find(k);
            printf("%d\n", below[k]);
        }
    }

    return 0;
}

10.1清北刷题记-LMLPHP

10-06 19:52