【考试反思】联赛模拟测试17

林sir \(\mathbb{AK}\)

气抖冷,林sir居然站起来了

我 = = 算了

不开 long long 见祖宗

T1: 30 \(\rightarrow\) 0

T1:简单的区间

简单分治 并不

一定要养成 #define int long long 的好习惯啊 (滑稽)

在分治时,先处理完本层跨过终点的合法区间,然后向下递归。在本层处理时,分最大值在中点左边和最大值在中点右边处理。下面以在中点左边为例:

设左右端点的指针是 \(i,j\),中点左边的和为 \(sumi\),中点右边的和为 \(sumj\)。合法区间需要满足 \(sumi+sumj-Max\equiv 0\pmod k\)。那么 \(i\) 一步步向左扩展,我们需要找到一个符合条件的 \(sumj\),我们只需要开桶维护即可,符合条件的 \(sumj\) 即是 \(k-sumi+Max\)

然后就是中点右面,反过来即可。

注意清空桶的时候不要 memset,否则会和暴力一个分。

HISKrrr:这真是板子题

Code
#include <bits/stdc++.h>
#define int long long
using namespace std;
const int maxn=1e6+10;
int n,K,ans;
int a[maxn];

inline int read(){
    int x=0;bool fopt=1;char ch=getchar();
    for(;!isdigit(ch);ch=getchar())if(ch=='-')fopt=0;
    for(;isdigit(ch);ch=getchar())x=(x<<3)+(x<<1)+ch-48;
    return fopt?x:-x;
}

int top;
int cnt[maxn],sta[maxn];
void Solve(int l,int r){
    if(l==r)return;
    int mid=(l+r)>>1;
    int i=mid,j=mid+1;
    int Max=0,sumi=0,sumj=0;
    for(i=mid;i>=l;i--){
        Max=max(Max,a[i]);sumi=(sumi+a[i])%K;
        while(a[j]<=Max&&j<=r){
            sumj=(sumj+a[j])%K;
            cnt[sumj]++;sta[++top]=sumj;
            j++;
        }
        ans+=cnt[((K-sumi+Max)%K+K)%K];
    }
    while(top)cnt[sta[top--]]=0;
    i=mid,j=mid+1;
    Max=0,sumi=0,sumj=0;
    for(j=mid+1;j<=r;j++){
        Max=max(Max,a[j]);sumj=(sumj+a[j])%K;
        while(a[i]<Max&&i>=l){//注意这不能取等了,否则会重
            sumi=(sumi+a[i])%K;
            cnt[sumi]++;sta[++top]=sumi;
            i--;
        }
        ans+=cnt[((K-sumj+Max)%K+K)%K];
    }
    while(top)cnt[sta[top--]]=0;
    Solve(l,mid);
    Solve(mid+1,r);
}

signed main(){
#ifndef LOCAL
    freopen("interval.in","r",stdin);
    freopen("interval.out","w",stdout);
#endif
    n=read();K=read();
    for(int i=1;i<=n;i++)
        a[i]=read();
    Solve(1,n);
    printf("%lld\n",ans);
    return 0;
}

T2:简单的玄学

很玄学。\(1\leq n\leq 10^{18},2\leq m\leq 10^{18}\)

显然答案是 \(1-\cfrac{(2^n)^{\underline m}}{2^{nm}}=1-\cfrac{\prod\limits_{i=2^n-m+1}^{2^n-1}i}{2^{n(m-1)}}\)。忽略前面的 \(1\) 算后面即可。但是存不下。注意到模数很小,所以可以在这上面下手。

所以我们发现当 \(m>10^6+3\) 的时候,取模一定是 \(0\) 了,直接 break 掉就行了。

所以还有约分这个事。发现能约的因子只有 \(2\)

对于任意一个 \(1\leq a<2^n\)\(a\)\(2^n-a\) 的中 2 的次数相同。

所以我们要求的就是 \((m-1)!\) 中因子 \(2\) 的个数。这个有一个 \(O(\log m)\) 的经典做法。

for(int i=2;i<=m;i<<=1)
    cnt+=m/i;

例如 \(m-1=9\),那以上代码就是模拟的以下过程:

1 × 2 × 3 × 4 × 5 × 6 × 7 × 8 × 9
    1       1       1       1     i=2
            1               1     i=4
                            1     i=8

发现每个数都正好被统计了 \(2\) 的因数个数次。

其实没必要真的去约分。我们求出来个数之后,\(a\)\(b\) 都乘上 \(2\) 的逆元的个数次方即可。

还有要注意的就是算分母的时候不要 qpow(2,n*m) 了,否则直接爆掉 long long

Code
#include <bits/stdc++.h>
#define int long long
using namespace std;
const int Mod=1e6+3;
const int inv2=500002;
int n,m;

inline int qpow(int x,int b){
    int ans=1,base=x;
    while(b){
        if(b&1)ans=ans*base%Mod;
        base=base*base%Mod;
        b>>=1;
    }
    return ans;
}

signed main(){
#ifndef LOCAL
    freopen("random.in","r",stdin);
    freopen("random.out","w",stdout);
#endif
    scanf("%lld%lld",&n,&m);
    if((double)log2(m)-(double)n>1e-6)return !puts("1 1");
    int a=1,p=qpow(2,n),b=qpow(p,m);
    for(int i=1;i<=m;i++){
        a=a*(p-i+1)%Mod;
        if(!a)break;
    }
    int cnt=n;m--;
    for(int i=2;i<=m;i<<=1)
        cnt+=m/i;
    a=a*qpow(inv2,cnt)%Mod;
    b=b*qpow(inv2,cnt)%Mod;
    printf("%lld %lld\n",(b-a+Mod)%Mod,b);
    return 0;
}

T3:简单的填数

瞎贪得 10 分

正解是贪心加模拟,比较麻烦,以后有时间补吧

T4:聪聪和可可

原题,但没做过。

用 bfs 预处理两点之间最短路距离和猫走的路径,然后可以用记忆化搜索简单转移。

Code
#include <bits/stdc++.h>
using namespace std;
const int maxn=1e3+10;
int n,m,ccst,kkst;
int deg[maxn];
double ans;

struct Edge{
    int from,to,nxt;
}e[maxn<<1];

inline int read(){
    int x=0;bool fopt=1;char ch=getchar();
    for(;!isdigit(ch);ch=getchar())if(ch=='-')fopt=0;
    for(;isdigit(ch);ch=getchar())x=(x<<3)+(x<<1)+ch-48;
    return fopt?x:-x;
}

int head[maxn],cnt;
inline void add(int u,int v){
    e[++cnt].from=u;
    e[cnt].to=v;
    e[cnt].nxt=head[u];
    head[u]=cnt;
}

int dis[maxn][maxn],p[maxn][maxn];//猫在i,鼠在j,猫下一步走p[i][j]
void bfs(int s){
    queue<int> q;
    q.push(s);
    while(!q.empty()){
        int u=q.front();q.pop();
        int temp=p[s][u];
        for(int i=head[u];i;i=e[i].nxt){
            int v=e[i].to;
            if(dis[s][v]==-1||(dis[s][u]+1==dis[s][v]&&temp<p[s][v])){
                dis[s][v]=dis[s][u]+1;
                p[s][v]=temp?temp:v;//p[s][s]==0 那v就是下一步
                q.push(v);
            }
        }
    }
}

double f[maxn][maxn];
double dfs(int cpos,int kpos){
    if(cpos==kpos)return 0;
    if(p[cpos][kpos]==kpos||p[p[cpos][kpos]][kpos]==kpos)return f[cpos][kpos]=1.0;
    if(f[cpos][kpos])return f[cpos][kpos];
    double sum=dfs(p[p[cpos][kpos]][kpos],kpos);
    for(int i=head[kpos];i;i=e[i].nxt){
        int v=e[i].to;
        sum+=dfs(p[p[cpos][kpos]][kpos],v);
    }
    return f[cpos][kpos]=1.0*sum/(deg[kpos]+1)+1;
}

int main(){
#ifndef LOCAL
    freopen("cchkk.in","r",stdin);
    freopen("cchkk.out","w",stdout);
#endif
    memset(dis,-1,sizeof(dis));
    n=read();m=read();ccst=read();kkst=read();
    for(int i=1;i<=m;i++){
        int u=read(),v=read();
        add(u,v);add(v,u);
        deg[u]++;deg[v]++;
    }
    for(int i=1;i<=n;i++)
        bfs(i);
    printf("%.3lf\n",dfs(ccst,kkst));
    return 0;
}
posted @ 2020-10-15 11:58  Midoria7  阅读(131)  评论(1编辑  收藏  举报