03-11考试总结

3月11日"考试"总结

你都没考你总结啥


T1

正解

对于01串 \(a\) , 我们在它后面加'0'
并定义其异或序列 : \(b\) , 有 \(b_{i}=a_{i} \oplus a_{i-1}\)
那么 , 每个\(a\)都有唯一的\(b\)与之对应
现在\(a\)的匹配变为\(b\)的匹配 , \(a\)的区间翻转变为\(b\)的两个位置的翻转

考虑怎么匹配 , 发现范围内的\(T\)的长度只有根号种
然后对于一个长度的\(T\) , 我们可以把\(S\)"折起来"计算
复杂度大概是\(n \sqrt n\)级别的 \(O(\)可过\()\)

上代码 :

#include<bits/stdc++.h>
#define MAXN(a) ((max##a)+10)
using namespace std;

const int maxn=200000,maxm=20000000;

struct str{
    int *p,tag; str *next;
    str(){tag=0,p=NULL,next=NULL;}
    ~str(){}
};

int n,m,tail,sed;
int s[MAXN(n)];
int t[MAXN(m)];
int p[MAXN(m)];
int cnt[2][MAXN(n)];
int ans[MAXN(m)];
str *beg[MAXN(m)];

inline void init(){
    {
        char k=getchar();int las=0;
        while(k!='a'&&k!='b')k=getchar();
        while(k=='a'||k=='b'){
            s[++n]=((k=='b')^las);
            las=(k=='b'),k=getchar();
        }s[++n]=sed=las;
    }
    scanf("%d",&m);
    for(int i=1;i<=m;i=-~i){
        char k=getchar();
        while(k!='a'&&k!='b')k=getchar();
        int len=0;str *now=new str();
        now->p=t+tail;now->tag=i;
        while(k=='a'||k=='b')
            now->p[++len]=(k=='b'),k=getchar();
        tail+=len;now->next=beg[len],beg[len]=now;
    }
    return;
}

inline void pre_work(int len){
    memset(cnt,0,sizeof(cnt));
    int ed=(n-1)/len*len+1;
    for(int i=len+1;i< ed;i++)
        cnt[s[i]][(i-1)%len+1]++;
}

inline void calc(str *st,int len){
    int &Ans=ans[st->tag];
    if(len+1<n){
        int ed=(n-1)/len*len+1;
        p[1]=st->p[1];
        for(int i=2;i<=len;i=-~i)
            p[i]=st->p[i]^st->p[i-1];

        for(int u=1;u<=len;u=-~u)
            Ans+=(s[u]!=p[u]);
        p[1]=st->p[1]^st->p[len];

        for(int k=1;k<=len;k=-~k)
            Ans+=cnt[p[k]^1][k];

        for(int u=ed;u<=n-1;u=-~u)
            Ans+=(s[u]!=p[u-ed+1]);

        Ans+=(st->p[(n-2)%len+1]!=sed);
    }
    else {
        p[1]=st->p[1];
        for(int i=2;i<=n-1;i=-~i)
            p[i]=st->p[i]^st->p[i-1];
        p[n]=st->p[n-1];
        for(int u=1;u<=n;u=-~u)
            Ans+=(s[u]!=p[u]);
    }
    return;
}

int main(){
#ifndef ONLINE_JUDGE
    freopen("string.in","r",stdin);
    freopen("string.out","w",stdout);
#endif
    init();
    int cnt=0;
    for(int i=1;i<=tail;i=-~i){
        if(beg[i]==NULL)continue;
        //printf("%d %d %d\n",n,i+1,n%(i+1));
        pre_work(i);str *u=beg[i];
        while(u!=NULL)
            calc(u,i),u=u->next;
    }
    for(int i=1;i<=m;i=-~i)
        printf("%d\n",(ans[i])>>1);
    return 0;
}

T2

得分情况 :

预计分数 : 15pts
实际得分 : 15pts
暴力搜就完事了

正解 :

先考虑"已知"从\(1\)\(n\)花费的时间的期望 , 设为\(l\)
那么有DP式 :

\[ f[u][j]=\frac{(\sum min( f[v][j-d[v]],H-(j-d[v])+l) )}{ot[u]}+1 \]
\(min\)里头那坨的意义是 , 你从\(u\)出发到\(v\) , 要么继续从\(v\)走 , 要么从\(v\)返回至起点
而返回至起点后 , 你需要在起点呆 \(H-(j-d[v])\) 的时间回血 , 然后用\(l\)的时间到\(n\)

知道了这个好像没啥用 , 题目要求的就是 \(l\) 的值
但我们发现有了这个后 , \(l\)就可以二分了
因为对于一个二分出的\(l\) , 如果它比\(l_{ans}\)大的话 , 一定有\(f[1][H]< l\)
完事 , 复杂度\(O(n^3*log_2n)\) , 可过

Code :

inline bool check(ldb limt){
    for(int i=1;i< n;i=-~i)
        for(int j=1;j<=H;j=-~j)
            f[i][j]=inf;
    for(int u=n-1;u>=1;u--){
        for(int j=mx[u]+1;j<=H;j=-~j){
            ldb res=0;if(!ot[u])continue;
            for(int i=head[u];i;i=e[i].next){
                int v=e[i].v;
                res+=min(f[v][j-d[v]],H-(j-d[v])+limt);
            }f[u][j]=(res/(ldb)ot[u])+1;
        }
    }return f[1][H]< limt;
}

int main(){
    r(n),r(m),r(H);
    for(int i=1;i<=m;i=-~i){
        int r(u),r(v);add(u,v);
    }
    for(int i=1;i<=n;i=-~i)r(d[i]);
    for(int u=1;u<=n;u=-~u)
        for(int i=head[u];i;i=e[i].next)
            mx[u]=max(mx[u],d[e[i].v]);
    ldb l=0,r=2000000,ans=0;
    while(l+eps<=r){
        ldb mid=(l+r)/2;
        if(check(mid))
            r=mid-eps,ans=mid;
        else l=mid+eps; 
    }
    if(ans>=1000000)puts("-1");
    else printf("%.6Lf",ans);
    return 0;
}

T3

正解

天上第一的找规律大师lunch发现了规律
我太菜了 , 只能抄他的代码维持生活
所以具体题解看这里
代码(抄的他的) :

#include<bits/stdc++.h>
#define r(a) (a)=read<int>()
#define rl(a) (a)=read<ll>()
#define MAXN(a) ((max##a)+10)
using namespace std;

typedef long long ll;
const int maxk=5000;
const int mod=1e9+7;

namespace Math{
    int C[MAXN(k)][MAXN(k)];
    inline ll quick_pow(ll a,ll b){
        ll ans=1;a%=mod,b%=(mod-1);
        while(b){
            if(b&1)ans=ans*a%mod;
            a=a*a%mod,b>>=1;
        }return ans;
    }
    inline ll inv(ll a){return quick_pow(a,mod-2);}
    inline void init(){
        for(int i=0;i<=maxk;i=-~i)
            for(int j=0;j<=i;j=-~j)
                if(j==0||i==j)C[i][j]=1;
                else C[i][j]=(C[i-1][j-1]+C[i-1][j])%mod;
    }
}

using Math::C;
using Math::inv;
using Math::quick_pow;

int K,R_,inv_;
ll n,R;
int n_[MAXN(k)];
int s[MAXN(k)];

int S(int k){
    if(s[k])return s[k];
    int res=1ll*n_[k]*R_%mod,det=0;
    for(int i=1;i<=k;i=-~i){
        det=1ll*C[k][i]*S(k-i)%mod;
        res=(res+((i&1)?-1ll:1ll)*det%mod)%mod;
    }return s[k]=1ll*(res%mod+mod)%mod*inv_%mod;
}

template<class T>inline T read();

signed main(){
#ifndef ONLINE_JUDGE
    freopen("sword.in","r",stdin);
    freopen("sword.out","w",stdout);
#endif
    Math::init();n_[0]=1;
    int T=read<int>();
    while(T--){
        r(K),rl(n),rl(R);R_=quick_pow(R,n+1);inv_=inv(R-1);
        for(int i=1;i<=K;i=-~i)n_[i]=1ll*n_[i-1]*((n)%mod)%mod;
        memset(s,0,sizeof(s));
        s[0]=1ll*(R_-(R%mod)+mod)%mod*inv_%mod;
        printf("%d\n",S(K));
    }
    return 0;
}

template<class T>inline T read(){
    T sum=0,f=1;char k=getchar();
    for(;k< '0'||'9'< k;k=getchar())
        if(k=='-')f=-1;
    for(;'0'<=k&&k<='9';k=getchar())
        sum=(sum<<1)+(sum<<3)+(k^48);
    return sum*f;
}


转载于:https://www.cnblogs.com/Pump-six/p/10518833.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值