18.9.26 考试总结

这道题我考试的时候没想出来 冷静分析一波

设一开始小$K$ 又$n$块芝麻 总共有$sum$块 那么小$X$有$sum - n$块

那么每次变化有两种情况 

1.$n$更小 那么$n$变成$2n$    

2.$n$更大 那么$sum - n$变成$2 * (sum - n)$ 共有$sum$块 那么$n$变为$sum - 2 * (sum - n) = 2n - sum$

这两个最终状态的$n$在模$sum$意义下是一样的 相当于没有变化..

所以就快速幂走一波就可以了

代码

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

typedef long long ll;
ll sum,n,m,k;

ll fast_pow(ll a, ll b, ll mod) {
    
    ll ans = 1;
    for(;b;b >>= 1,a = a * a % mod)
        if(b & 1) ans = ans * a % mod;
    return ans;
}

int main( ) {
    
    freopen("sesame.in","r",stdin);
    freopen("sesame.out","w",stdout);
    scanf("%lld%lld%lld",& n,& m,& k);
    sum = n + m;
    ll del = fast_pow(2, k, sum);
    n = n * del % sum;
    printf("%lld\n",min(sum - n, n));
}

然后这道题我考试的时候是 想!出!来!正!解!了!的!

然后对拍老不过 死的明明北北QAQAQAQAQ

考试完了两分钟就改出来了!!!少了一句特判!!!掉了50分!!!!

这道题题目是 $a_{x} = q\cdot a_{y} + K$ 那么也就是说$a_{x} - K$是$a_{y}$的倍数 若一对数满足这个条件 则这对数是坏对 

那么我们扫一遍 对于每个位置$i$找出以$i$作为区间结尾的区间个数就可以了

所以考虑如何在前面的数中找出一对坏对最后出现的位置 也就是$$的倍数 也就是从那个位置之后的位置都可以作为合法区间的开头

然后看到数的范围比较小 所以就考虑开桶 $pos[i]$表示$i$的倍数最后出现的位置

对于每一个位置的$a[i] - K$ 处理出他的所有因子 更新这些$pos$即可

这时候少了一些特判 如果一个数小于等于$K$那么模它之后不可能等于$K$ 也就是说它模任何数都合法 就不去更新现在的最后不合法位置

另外如果这个数等于$K$ 那么之后小于等于他的数刚才已经说了就不管了 大于他的数则一定与他形成坏对 所以还要记录他的位置 遇到大于$K$的位置时更新最后不合法的位置

然后搞一搞就可以了

代码

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

const int N = 1e5 + 5;
int n,MOD,pos[N],a[N];
long long ans = 0;

void Init( ) {
    
    scanf("%d%d",& n,& MOD);
    for(int i = 1;i <= n;i ++) scanf("%d",& a[i]);
}

void work(int x, int p) {
    
    for(int i = 1;i * i <= x;i ++) {
        if(x % i == 0) pos[i] = p, pos[x / i] = p;
    }
}

void Solve( ) {
    
    int las = 0,tag = 0;
    for(int i = 1;i <= n;i ++) {
        int pre = pos[a[i]];
        if(a[i] > MOD) las = max(max(las, pre), tag);
        ans += 1ll * max(i - las, 0);
        if(a[i] - MOD > 0) work(a[i] - MOD, i);
        if(a[i] == MOD) tag = i;
    }
    printf("%lld\n", ans);
}

int main( ) {
    
    freopen("drink.in","r",stdin);
    freopen("drink.out","w",stdout);
    Init( );
    Solve( );
}

这道题是是一道dp题 其实还是挺难的 题解写在注释了

代码

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

typedef long long ll;
const int N = 5e3 + 5;
const int M = 1e6 + 5;
int n,m,l[M];
ll MOD,p[M],fac[M],d[2][N],f[N][N];

void Init( ) {
    
    scanf("%d%d%lld",& n,& m,& MOD);
    p[0] = 1;  fac[0] = 1;
    for(int i = 1;i <= m;i ++) p[i] = p[i - 1] * (m - i + 1) % MOD;//P(m,i) 
    for(int i = 1;i <= m;i ++) fac[i] = fac[i - 1] * i % MOD;//阶乘 
    for(int i = 1;i <= n;i ++) scanf("%d",& l[i]);
    
    f[1][1] = 1;
    for(int i = 2;i <= 5000;i ++)
        for(int j = 1;j <= i;j ++)//每个点只有两种选择 选新颜色或者旧颜色  
            f[i][j] = ((f[i - 1][j - 1] + f[i - 1][j] * (j - 1) % MOD) % MOD + MOD) % MOD;//在i个格子里选择j种颜色的合法方案 
}

void Solve( ) {
    
    int now = 0;
    for(int i = 1;i <= l[1];i ++) d[now][i] = p[i] * f[l[1]][i] % MOD;//第1层选择i种颜色的方案数 
    for(int i = 2;i <= n;i ++) {
        ll sum = 0; now ^= 1;
        for(int j = 1;j <= l[i - 1];j ++) 
            sum = (sum + d[now ^ 1][j]) % MOD;
        for(int j = 1;j <= l[i];j ++) {
            d[now][j] = (p[j] * f[l[i]][j] % MOD) * sum % MOD;
            if(j <= l[i - 1]) d[now][j] = (d[now][j] - (d[now ^ 1][j] * f[l[i]][j] % MOD * fac[j] % MOD) + MOD) % MOD;
        }//除去不合法的方案 因为上一层的颜色是确定的 所以乘阶乘而不是P 
    }
    ll ans = 0;
    for(int i = 1;i <= l[n];i ++) ans = (ans + d[now][i]) % MOD;
    printf("%lld\n",ans);
}

int main( ) {
    
    freopen("kalanchoe.in","r",stdin);
    freopen("kalanchoe.out","w",stdout);
    Init( );
    Solve( );
}

转载于:https://www.cnblogs.com/Rubenisveryhandsome/p/9707766.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值