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+...+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;
}