Codeforces Round #448 (Div. 2)

A. Pizza Separation

枚举连续的即可。

#include <bits/stdc++.h>
using namespace std;
using ll=long long;
int n,x;
int a[780];

int main(){
    //freopen("in.txt","r",stdin);
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
        scanf("%d",a+i),a[i+n]=a[i];
    for(int i=1;i<=n+n;i++)
        a[i]=a[i-1]+a[i];
    int mn=360;
    for(int i=1;i<=n;i++)
        for(int j=i;j<=i+n-1;j++)
            mn=min(mn,abs(abs(a[j]-a[i-1])*2-360));
    cout<<mn;
    return 0;
}

B. XK Segments

对于$a_i$,大于等于他的x的倍数的第k个可以迅速求出来。
那么就变成求这一段区间的数字的个数。二分即可。

#include <bits/stdc++.h>
using namespace std;
using ll=long long;
const int mod = 1e9+7;
int n;
ll x,k;
ll a[100005];
int main(){
    //freopen("in.txt","r",stdin);
    scanf("%d%lld%lld",&n,&x,&k);
    for(int i=1;i<=n;i++)
        scanf("%lld",&a[i]);
    sort(a+1,a+1+n);
    ll res=0;
    for(int i=1;i<=n;i++){
        ll l=max(a[i],((a[i]-1)/x+k)*x),r=((a[i]-1)/x+k+1)*x;
        ll tmp=upper_bound(a+1,a+1+n,r-1)-lower_bound(a+1,a+1+n,l);
        res+=max(0ll,tmp);
    }
    cout<<res;
    return 0;
}

C. Square Subsets

将所有数字分解因子之后会变成 $a_i = 2^{p_1}+3^{p_2}+...+7^{p_4}+...$。
最大质因子大于7的数字只会有一个质因子,此列只会有一个非0系数。
那么原题就会变成满足: $x_1p_1+x_2p_2+...+x_np_n \equiv 0 (\mod 2)$的方程组。
求其解的个数,等于求矩阵的秩。
求出秩为$k$,答案是$2^{n-k}-1$。
Q老师的写法。

#include <bits/stdc++.h>
using namespace std;
using ll=long long;
const int mod = 1e9+7;
int n,x;
int p[100],top=0;
vector<int> v;
bool isprime(int n){
    for(int i=2;i*i<=n;i++)
        if(n%i==0) return 0;
    return 1;
}
int main(){
    //freopen("in.txt","r",stdin);
    for(int i=2;i<=70;i++)
        if(isprime(i)) p[top++]=i;
    scanf("%d",&n);
    for(int i=1;i<=n;i++){
        scanf("%d",&x);
        int t=0;
        for(int j=0;j<top;j++){
            if(x%p[j]) continue;
            while(x%p[j]==0){
                t^=(1<<j);
                x/=p[j];
            }
        }
        for(auto ex:v)
            t=min(t,t^ex);
        if(t) v.push_back(t);
    }
    int res=1;
    //cout<<v.size()<<endl;
    for(int i=(int)v.size();i<n;i++)
        res=(res+res)%mod;
    res=(res-1+mod)%mod;
    cout<<res;
    return 0;
}

D. String Mark

转换为求比$S_2$小的和比$S_1$小的答案之差再减去1。
对于当前点,计算两种状态。
1.已经可以决定拼出长度比对比串小,即ch<s[i]。后面应该是$\frac{len!}{l_1!l_2!...l_k!}$,边除边做就能$O(1)$。
2.当前状态保持相等。

#include <bits/stdc++.h>

using namespace std;
using ll=long long;
const int mod = 1e9+7;
const int maxn = 1e6+5;
char s1[maxn],s2[maxn];
ll fac[maxn],inv[maxn];
int len,n;
int cnt[128];

inline ll power(ll a,ll b){
    if(!b) return 1ll;
    ll ret=power(a,b>>1);
    ret=ret*ret%mod;
    if(b&1) return ret*a%mod;
    return ret;
}

void init(){
    #define N maxn-1
    fac[0]=1;
    for(ll i=1;i<=N;i++)
        fac[i]=fac[i-1]*i%mod;
    inv[N]=power(fac[N],mod-2);
    for(ll i=N;i>=1;i--)
        inv[i-1]=inv[i]*i%mod;
    //cout<<inv[0]<<endl;
}

ll calc(char s[],int n){
    memset(cnt,0,sizeof cnt);
    for(int i=0;i<n;i++)
        cnt[s1[i]]++;
    ll tmp=fac[n];
    for(int i='a';i<='z';i++)
        tmp=tmp*inv[cnt[i]]%mod;//all
    ll ret=0;
    for(int i=0;i<n;i++){
        tmp=tmp*power(n-i,mod-2)%mod;//n-i
        for(int x='a';x<s[i];x++)
            if(cnt[x])
                ret=(ret+tmp*cnt[x]%mod)%mod;
        tmp=tmp*cnt[s[i]]%mod;
        cnt[s[i]]--;
        if(cnt[s[i]]<0) return ret;
    }
    return ret;
}

int main(){
    //freopen("in.txt","r",stdin);
    init();
    scanf("%s%s",s1,s2);
    n=strlen(s1);
    ll res=calc(s2,n)-calc(s1,n);
    res--;
    res=(res%mod+mod)%mod;
    cout<<res;
    return 0;
}

E. Eyes Closed

查询时查询区间和。
修改时,
假设左边区间值为left长度为l1,右边值为right长度为l2。
修改左边其实是左边每个值都有1/l1的几率换掉,那么就是有(l1-1)/l1的概率保存下来。
保留下来的期望就是s*(l1-1)/l1再加上右边换过来的期望right/l2/l1。
维护三个标记即可。

#include <bits/stdc++.h>
using namespace std;
using ll=long long;
using db=double;
const int mod = 1e9+7;
const int maxn = 1e5+5;
int n,m,opt,l[2],r[2];
int a[maxn];
int len[maxn<<4];
struct tree{
    db s,mul,add;
}T[maxn<<4];

void pup(int id){
    T[id].s=T[id<<1].s+T[id<<1|1].s;
}
void pdd(int id){
    T[id<<1].s=T[id<<1].s*T[id].mul+T[id].add*len[id<<1];
    T[id<<1|1].s=T[id<<1|1].s*T[id].mul+T[id].add*len[id<<1|1];
    T[id<<1].add=T[id<<1].add*T[id].mul+T[id].add;
    T[id<<1|1].add=T[id<<1|1].add*T[id].mul+T[id].add;
    T[id<<1].mul=T[id<<1].mul*T[id].mul;
    T[id<<1|1].mul=T[id<<1|1].mul*T[id].mul;
    T[id].add=0;
    T[id].mul=1;
}

void build(int l,int r,int id){
    T[id].mul=1;
    T[id].add=0;
    len[id]=r-l+1;
    if(l==r){
        T[id].s=a[l];
        return ;
    }
    int mid=(l+r)/2;
    build(l,mid,id<<1);
    build(mid+1,r,id<<1|1);
    pup(id);
}

void update(int L,int R,db d,db rat,int l,int r,int id){
    if(L<=l&&r<=R){
        T[id].s=T[id].s*rat+d*len[id];
        T[id].add=T[id].add*rat+d;
        T[id].mul=T[id].mul*rat;
        return;
    }
    pdd(id);
    int mid=(l+r)/2;
    if(mid>=L) update(L,R,d,rat,l,mid,id<<1);
    if(mid<R) update(L,R,d,rat,mid+1,r,id<<1|1);
    pup(id);
}

db query(int L,int R,int l,int r,int id){
    if(L<=l&&r<=R){
        return T[id].s;
    }
    pdd(id);
    int mid=(l+r)/2;
    if(mid>=R) return query(L,R,l,mid,id<<1);
    else if(mid<L) return query(L,R,mid+1,r,id<<1|1);
    else return query(L,R,l,mid,id<<1)+query(L,R,mid+1,r,id<<1|1);
}

int main(){
    //freopen("in.txt","r",stdin);
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)
        scanf("%d",a+i);
    build(1,n,1);
    while(m--){
        scanf("%d",&opt);
        if(opt==1){
            scanf("%d%d%d%d",&l[0],&r[0],&l[1],&r[1]);
            db left=query(l[0],r[0],1,n,1);
            db right=query(l[1],r[1],1,n,1);
            update(l[0],r[0],right/(r[1]-l[1]+1)/(r[0]-l[0]+1),1.0*(r[0]-l[0])/(r[0]-l[0]+1),1,n,1);
            update(l[1],r[1],left/(r[0]-l[0]+1)/(r[1]-l[1]+1),1.0*(r[1]-l[1])/(r[1]-l[1]+1),1,n,1);
        } else {
            scanf("%d%d",&l[0],&r[0]);
            db res=query(l[0],r[0],1,n,1);
            printf("%.12lf\n",res);
        }
    }
    return 0;
}

转载于:https://www.cnblogs.com/foreignbill/p/7906837.html

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值