牛客OI赛制测试赛2补题

版权声明:转就转吧~~记得声明噢~~ https://blog.csdn.net/Soul_97/article/details/82469541

传送

A无序数组

a,b最大是1e5  先暴力打表因子数(第一个双循环)

题中要求是无序的  所以要去掉重复的   根据例子我们可以发现  重复的组数是 C(相同因子数,2)  即一个组合数

相同因子数直接求两个数的gcd即可 然后a[gcd]对应的就是相同的因子数

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int INF = 0x3f3f3f3f;
const int N = 1e5 + 5;
const int mod = 1e9 + 7;

int a[N];

int main()
{
    for(int i = 1;i <= 100000;i ++)
    {
        for(int j = 1;i * j <= 100000;j ++)
            a[i * j] ++;
    }

    int T, n, m;
    scanf("%d",&T);
    while(T --)
    {
        scanf("%d%d",&n,&m);

        int gcd = __gcd(n,m);

        printf("%d\n",a[n]*a[m] - a[gcd]*(a[gcd]-1)/2);
    }
    return 0;
}

B 路径数量

01矩阵,相当于一个点到另一个点的距离为1 

b数组的 i表示 到达i地  j表示走j步  那么最终达到的条件就是 b[n][k] 即到达 n点用k步  初始化b[1][0] = 1 

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int INF = 0x3f3f3f3f;
const int N = 35;
const int mod = 1e9 + 7;

ll a[N][N], b[N][N];
int n, K;

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

    for(int i = 1;i <= n;i ++)
    {
        for(int j = 1;j <= n;j ++)
            cin >> a[i][j];
    }

    b[1][0] = 1;

    for(int k = 1;k <=K;k ++)
    {
        for(int i = 1;i <= n;i ++)
        {
            for(int j = 1;j <= n;j ++)
            {
                if(a[i][j])
                    b[j][k] += b[i][k-1];
            }
        }
    }
    cout << b[n][K] << endl;
    return 0;
}

话说这种问题是矩阵乘法问题  k长路径数 即求矩阵k次幂然后 a[1][n]即是答案

#include <bits/stdc++.h>
using namespace std;
 
typedef long long ll;
typedef vector<ll> vec;
typedef vector<vec> mat;
mat mul(mat& A, mat& B)
{
    mat C(A.size(), vec(B[0].size()));
    for (int i = 0; i < A.size(); i++)
        for (int k = 0; k < B.size(); k++)
            if (A[i][k])
                for (int j = 0; j < B[0].size(); j++)
                    C[i][j] = (C[i][j] + A[i][k] * B[k][j]);
    return C;
}
mat Pow(mat A, ll n)
{
    mat B(A.size(), vec(A.size()));
    for (int i = 0; i < A.size(); i++) B[i][i] = 1;
    for (; n; n >>= 1, A = mul(A, A))
        if (n & 1) B = mul(B, A);
    return B;
}
 
int main()
{
#ifndef ONLINE_JUDGE
    freopen("1.in", "r", stdin);
    freopen("1.out", "w", stdout);
#endif
    int n, k;
    scanf("%d%d", &n, &k);
    mat G(n, vec(n));
    for (int i = 0; i < n; i++)
        for (int j = 0; j < n; j++)
            scanf("%lld", &G[i][j]);
    G = Pow(G, k);
    printf("%lld\n", G[0][n - 1]);
    return 0;
}

C数列下标

昨天应该是数据出了锅。。 段错误

其实暴力可过

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int INF = 0x3f3f3f3f;
const int N = 1e4 + 5;
const int mod = 1e9 + 7;
 
ll a[N],b[N];
 
int main()
{
    int n;
    scanf("%d",&n);
    memset(b,INF,sizeof(b));
    for(int i = 1;i <= n;i ++)
        scanf("%lld",&a[i]);
 
    for(int i = n;i > 1;i --)
    {
        for(int j = 1;j < i;j ++)
        {
            if(a[i] > a[j] && i < b[j])
                b[j] = i;
        }
    }
 
    for(int i = 1;i <= n;i ++)
    {
        if(i != 1)
            printf(" ");
 
        if((int)b[i] == INF)
            printf("0");
        else
            printf("%d",b[i]);
    }
    return 0;
}

D 烛光晚餐

规律就是 开关n次之后 只有平方数会亮着  即求平方数的个数即可

1.可以暴力打表找规律

2(数学)详细可参考 http://www.cnblogs.com/haolujun/archive/2012/10/10/2719031.html

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int INF = 0x3f3f3f3f;
const int N = 1e4 + 5;
const int mod = 1e9 + 7;


int main()
{
    ll n, ans;
    cin >> n;
    cout << (ll)sqrt(n) << endl;
    return 0;
}

E 括号序列

设置两个记录左右括号带匹配数量的变量 l, r 初始为0

然后遍历整个串

如果遇到左括号 ( 那么 l++  如果遇到右括号  判断当前待匹配左括号是否为0  不为0 就匹配一个  l--

否则的话  待匹配右括号数量+1 即 r++

最后匹配次数即为 带匹配括号的一半

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int INF = 0x3f3f3f3f;
const int N = 5e6 + 5;
const int mod = 1e9 + 7;

char a[N];
int main ()
{
    int l, r, n;
    scanf("%d",&n);
    l = r = 0;

    scanf("%s",a);

    for(int i = 0;i < n;i ++)
    {
        if(a[i] == '(')
            l ++;
        else
        {
            if(l != 0)
                l --;
            else
                r ++;
        }
    }
    cout << (l + 1) / 2 << endl;
    return 0;
}

F 假的数学游戏

比赛的时候没想到啥好方法。。因为给范围了 拿py直接暴力打了表 拿了前几个数据  

参考了这个大佬的思想https://blog.csdn.net/milkyyyyy/article/details/82490607

先看这个式子

我们就可以把题中的 N! 恰好大于 X^X转换在log下进行计算   当log的底数大于1时时递增的  所以

若 logax>logay 则 x>y

于是有了新的打表程序。。。。

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int INF = 0x3f3f3f3f;
const int N = 5e6 + 5;
const int mod = 1e9 + 7;

double n, x, m;

int main ()
{

    while(cin >> x)
    {
        n = m = 0;

        x *= log(x);

        while(1)
        {
            n += log(++m);
            if(n > x)
                break;
        }

        cout << m << endl;
    }

    return 0;
}

这个我挂了十多分钟把。。。出来全部结果

然后就可以愉快的交代码了。

#include<bits/stdc++.h>
using namespace std;
int main() {
   long long a[15] = {10,94,892,8640,84657,834966,8267019,82052137,815725636,8118965902};
    string ss;cin>>ss;
    cout<<a[ss.size()-1]<<endl;
}

正解:

不会写。。

贴一个蔡队的正解代码

#include <bits/stdc++.h>
using namespace std;
 
typedef long long ll;
ll count(ll n)
{
    if (n == 1) return 1;
    return static_cast<ll>(ceil(0.5 * log10(2 * M_PI * n) + n * log10(n) - n * log10(M_E)));
}
 
int main()
{
#ifndef ONLINE_JUDGE
    freopen("1.in", "r", stdin);
    freopen("1.out", "w", stdout);
#endif
    ll x;
    cin >> x;
    ll cnt = static_cast<ll>(log10(x) * x) + 1;
    ll l = 1, r = 1e12, ans;
    while (l <= r)
    {
        ll m = l + r >> 1;
        ll tmp = count(m);
        // cerr << m << " " << tmp << endl;
        if (tmp > cnt)
            r = m - 1,
            ans = m;
        else
            l = m + 1;
    }
    cout << ans << endl;
    return 0;
}

猜你喜欢

转载自blog.csdn.net/Soul_97/article/details/82469541