A. WSI Extreme

将人按洗澡时间从大到小排序,那么$ans=\sum_{i=1}^{n}a_i\times\lfloor\frac{i+W-1}{W}\rfloor$。

当$W$比较大时,暴力枚举每一段,然后求和即可,权值线段树维护。

当$W$比较小时,线段树上按排名模$W$的值维护$W$个量即可。

时间复杂度$O(q\sqrt{W}\log n)$。

B. Average

枚举平均数然后容斥+隔板法计算方案数即可。

#include <bits/stdc++.h>
using namespace std ; typedef long long LL ;
const int mod=1e9+7,Maxn=60*202;
void up(int &x,int y){x+=y;if(x>=mod)x-=mod;}
int rev[Maxn],fac[Maxn];
int C(int x,int y){
if(x<y||y<0)return 0;
return 1LL*fac[x]*rev[y]%mod*rev[x-y]%mod;
}
void solve(){
fac[0]=fac[1]=rev[0]=rev[1]=1;
for(int i=2;i<Maxn;i++)fac[i]=1LL*fac[i-1]*i%mod;
for(int i=2;i<Maxn;i++)rev[i]=1LL*(mod-mod/i)*rev[mod%i]%mod;
for(int i=2;i<Maxn;i++)rev[i]=1LL*rev[i-1]*rev[i]%mod;
}
int check(int sum,int n,int m){
int ret=0;
for(int i=0;i<=n;i++){
int tmp=1LL*C(n,i)*C(sum+n-i*(m+1)-1,n-1)%mod;
//if(i==1)printf("t1=%d t2=%d\n",C(n,i),C(sum+n-i*(m+1)-1,n-1));
if(i&1)tmp=(mod-tmp)%mod;
up(ret,tmp);
//printf("ret=%d\n",ret);
}
return ret;
}
int main () {
solve(); //printf("t2=%d\n",check(2,2,1));
int n,m;
while(scanf("%d%d",&n,&m)!=EOF){
if(!n&&!m)break;
int ans=0;
for(int i=0;i<=m;i++){
up(ans,1LL*check((n-1)*i,n-1,m)%mod);
}
//printf("t1=%d\n",check(0,2,1)); //printf("t2=%d\n",check(2,2,1));
ans=1LL*ans*n%mod;
printf("%d\n",ans);
}
return 0 ;
}

  

C. Big Bang

$ans=\sum_{i=1}^n\mu(i)\lfloor\frac{n}{i}\rfloor^4$。

D. Find C

首先通过exgcd求出一组解,然后往两侧延伸$K$个即可。

#include <bits/stdc++.h>
using namespace std ; typedef long long LL ;
const LL LIM=100000000000000LL;
typedef pair<LL,LL>pi;
LL sx,sy,ex,ey;
int K;
LL gcd(LL x,LL y){
if(!x)return y;
if(!y)return x;
return __gcd(x,y);
}
inline LL exgcd(LL a,LL b,LL &x,LL &y){
if(!b)return x=1,y=0,a;
LL d=exgcd(b,a%b,y,x);
y-=a/b*x;
return d;
}
int ok(LL x,LL y){
if(abs(x)>LIM||abs(y)>LIM)return 0;
return 1;
}
bool check(LL x,LL y){
if(x==sx&&y==sy)return 0;
if(x==ex&&y==ey)return 0;
if(__gcd(abs(x-sx),abs(y-sy))>1)return 0;
if(__gcd(abs(x-ex),abs(y-ey))>1)return 0;
return 1;
}
/*
void getst(LL &x,LL &y,LL stepx,LL stepy){
if(!stepx){
if(stepy<0){
y%=-stepy;
}
else {
y%=stepy;
}
}
else
if(!stepy){
x%=stepx;
}
else{
if(stepy>0){
LL
}
}
}
*/
set<pi>res;
void solve(LL S){
LL A=abs(sy-ey),B=abs(sx-ex);
LL gc=gcd(A,B);
LL tA=(sy-ey)/gc,tB=(ex-sx)/gc;
LL ftA=abs(tA),ftB=abs(tB);
LL C=S-(sx*ey-ex*sy);
C/=gc;
LL x,y;
exgcd(ftA,ftB,x,y);
if(ftB){
x=x*(C%ftB)%ftB;
y=(C-x*ftA)/ftB;
}
else{
y=y*(C%ftA)%ftA;
x=(C-y*ftB)/ftA;
}
if(tA<0)x=-x;
if(tB<0)y=-y;
LL stepx=(ex-sx)/gc,stepy=(ey-sy)/gc;
//if(!ok(x,y))while(1);
for(LL curx=x+stepx,cury=y+stepy;res.size()<K&&ok(curx,cury);curx+=stepx,cury+=stepy){
if(check(curx,cury)){
//printf("curx=%lld cury=%lld\n",curx,cury);
res.insert(pi(curx,cury));
}
} for(LL curx=x,cury=y;res.size()<K&&ok(curx,cury);curx-=stepx,cury-=stepy){
if(check(curx,cury)){
res.insert(pi(curx,cury));
}
}
}
int main () {
int _;scanf("%d",&_);
while(_--){
scanf("%lld%lld%lld%lld%d",&sx,&sy,&ex,&ey,&K);
if(ex<sx){swap(sx,ex);swap(sy,ey);}
res.clear();
LL S=__gcd(abs(sx-ex),abs(sy-ey));
solve(S);
solve(-S);
if(res.size()<K)while(1);
for(set<pi>::iterator it=res.begin();it!=res.end();it++){
printf("%lld %lld\n",it->first,it->second);
}
}
return 0 ;
}

  

E. ACM Tax

可持久化线段树维护即可。

#include<cstdio>
#include<algorithm>
#include<cstdlib>
#include<cstring>
using namespace std;
typedef long long ll;
const int N=50010,M=N*20;
int T,C;
int n,m,i,x,y,z,g[N],v[N<<1],w[N<<1],nxt[N<<1],ed;
int f[N],d[N],size[N],son[N],top[N];
int tot,rt[N],l[M],r[M],val[M];
inline void add(int x,int y,int z){v[++ed]=y;w[ed]=z;nxt[ed]=g[x];g[x]=ed;}
int ins(int x,int a,int b,int c){
int y=++tot;
val[y]=val[x]+1;
if(a==b)return y;
int mid=(a+b)>>1;
if(c<=mid){
l[y]=ins(l[x],a,mid,c);
r[y]=r[x];
}else{
l[y]=l[x];
r[y]=ins(r[x],mid+1,b,c);
}
return y;
}
void dfs(int x){
size[x]=1;
for(int i=g[x];i;i=nxt[i])if(v[i]!=f[x]){
f[v[i]]=x,d[v[i]]=d[x]+1;
rt[v[i]]=ins(rt[x],1,100000,w[i]);
dfs(v[i]),size[x]+=size[v[i]];
if(size[v[i]]>size[son[x]])son[x]=v[i];
}
}
void dfs2(int x,int y){
top[x]=y;
if(son[x])dfs2(son[x],y);
for(int i=g[x];i;i=nxt[i])if(v[i]!=son[x]&&v[i]!=f[x])dfs2(v[i],v[i]);
}
inline int lca(int x,int y){
for(;top[x]!=top[y];x=f[top[x]])if(d[top[x]]<d[top[y]])swap(x,y);
return d[x]<d[y]?x:y;
}
inline int kth(int x,int y,int z,int k){
int a=1,b=100000,mid,t;
while(a<b){
mid=(a+b)>>1;
t=val[l[x]]+val[l[y]]-2*val[l[z]];
if(k<=t){
b=mid;
x=l[x];
y=l[y];
z=l[z];
}else{
k-=t;
a=mid+1;
x=r[x];
y=r[y];
z=r[z];
}
}
return a;
}
inline int query(int x,int y){
int z=lca(x,y);
int all=d[x]+d[y]-d[z]*2;
if(all&1)return kth(rt[x],rt[y],rt[z],(all+1)/2)*2;
return kth(rt[x],rt[y],rt[z],all/2)+kth(rt[x],rt[y],rt[z],all/2+1);
}
int main(){
scanf("%d",&T);
for(C=1;C<=T;C++){
scanf("%d",&n);
ed=0;
for(i=1;i<=n;i++)g[i]=f[i]=d[i]=size[i]=son[i]=top[i]=rt[i]=0;
for(i=1;i<n;i++)scanf("%d%d%d",&x,&y,&z),add(x,y,z),add(y,x,z);
dfs(1);
dfs2(1,1);
scanf("%d",&m);
while(m--)scanf("%d%d",&x,&y),printf("%.1f\n",0.5*query(x,y));
for(i=1;i<=tot;i++)l[i]=r[i]=val[i]=0;
tot=0;
}
}

  

F. Dictionary Game

建出Trie树,然后就是经典树上删边游戏。

#include<cstdio>
#include<algorithm>
#include<cstdlib>
#include<cstring>
using namespace std;
typedef long long ll;
const int N=100010*40;
int T,C,tot,son[N][26],sg[N],f[N];
int n,i,j;
inline int ins(){
static char s[99];
scanf("%s",s);
int l=strlen(s);
int x=0;
for(int i=0;i<l;i++){
int w=s[i]-'a';
if(!son[x][w]){
son[x][w]=++tot;
f[tot]=x;
}
x=son[x][w];
}
return x;
}
inline void cal(int x){
sg[x]=0;
for(int i=0;i<26;i++)if(son[x][i])sg[x]^=sg[son[x][i]]+1;
}
void dfs(int x){
for(int i=0;i<26;i++)if(son[x][i])dfs(son[x][i]);
cal(x);
}
inline void up(int x){
while(x){
cal(x);
x=f[x];
}
cal(0);
}
int main(){
scanf("%d",&T);
for(C=1;C<=T;C++){
printf("Case %d:\n",C);
scanf("%d",&n);
while(n--)ins();
dfs(0);
scanf("%d",&n);
while(n--){
up(ins());
puts(sg[0]?"1":"2");
}
for(i=0;i<=tot;i++)for(j=f[i]=sg[i]=0;j<26;j++)son[i][j]=0;
tot=0;
}
}

  

G. Binary Strings

矩阵快速幂优化DP转移。

#include <bits/stdc++.h>
using namespace std ; typedef long long LL ;
const int mod=1e9+7;
void up(int &x,int y){x+=y;if(x>=mod)x-=mod;}
struct Mat{
int a[3][3];
Mat operator *(const Mat&x)const{
Mat ret;
for(int i=0;i<3;i++){
for(int j=0;j<3;j++){
int t=0;
for(int k=0;k<3;k++){
up(t,1LL*a[i][k]*x.a[k][j]%mod);
}
ret.a[i][j]=t;
}
}
return ret;
}
void init(int t){
for(int i=0;i<3;i++){
for(int j=0;j<3;j++){
a[i][j]=i==j?t:0;
}
}
}
}ori;
Mat powmod(Mat x,LL y){
Mat ret;
ret.init(1);
while(y){
if(y&1){ret=ret*x;}
y>>=1;
x=x*x;
}
return ret;
}
int go(LL x){
Mat tmp=powmod(ori,x+1);
return tmp.a[0][2];
}
void solve(){
LL l,r,k;
scanf("%lld%lld%lld",&l,&r,&k);
ori.init(0);
ori.a[0][0]=1;
ori.a[0][1]=1;
ori.a[1][0]=1;
ori=powmod(ori,k);
ori.a[0][2]=1;
ori.a[1][2]=1;
ori.a[2][2]=1;
ori.a[2][0]=ori.a[2][1]=0;
int ans=go(r/k);
ans-=go((l-1)/k);
if(ans<0)ans+=mod;
printf("%d\n",ans);
}
int main () {
int _,cas=1;scanf("%d",&_);
while(_--){
printf("Case %d: ",cas++);
solve();
}
return 0 ;
}

  

H. Witcher Potion

$f[S][i][j][k]$表示已经使用过的药水集合为$S$,当前能量为$i$,毒性为$j$,上一次是否嗑药为$k$时最多能打多少只怪物,然后DP即可。

#include<cstdio>
#include<algorithm>
#include<cstdlib>
#include<cstring>
using namespace std;
typedef long long ll;
const int inf=10000000;
int T,K,M,n,i,j,k,ans,t,e[11],p[11],f[1<<8][111][111][2],o;
inline void up(int&x,int y){if(x<y)x=y;}
int main(){
scanf("%d",&T);
while(T--){
scanf("%d%d%d",&K,&M,&n);
for(i=0;i<n;i++)scanf("%d",&e[i]);
for(i=0;i<n;i++)scanf("%d",&p[i]);
for(i=0;i<1<<n;i++)for(j=1;j<=100;j++)for(k=0;k<100;k++)f[i][j][k][0]=f[i][j][k][1]=-inf;
up(f[0][100][0][0],0);
for(i=0;i<1<<n;i++)for(j=100;j;j--)for(k=99;~k;k--)for(o=0;o<2;o++)if(f[i][j][k][o]>=0){
//kill a monster
if(j>K)up(f[i][j-K][max(0,k-M)][0],f[i][j][k][o]+1);
//drink
if(!o)for(t=0;t<n;t++)if(!(i>>t&1)){
if(k+p[t]<100)up(f[i|(1<<t)][min(100,j+e[t])][k+p[t]][1],f[i][j][k][o]);
} }
ans=0;
for(i=0;i<1<<n;i++)for(j=1;j<=100;j++)for(k=0;k<100;k++){
up(ans,f[i][j][k][0]);
up(ans,f[i][j][k][1]);
}
printf("%d\n",ans);
}
}

  

I. Sky Tax

根据根与询问点的位置关系分类讨论即可。

#include<cstdio>
#include<algorithm>
#include<cstdlib>
using namespace std;
typedef long long ll;
const int N=1000010,M=2000010;
int T,C,n,m,root,x,y,i,g[N],v[N<<1],nxt[N<<1],ed;
int st[N],en[N],size[N],dfn;
int son[N],top[N],d[N],f[N];
inline void add(int x,int y){
v[++ed]=y;nxt[ed]=g[x];g[x]=ed;
}
void dfs(int x){
size[x]=1;
for(int i=g[x];i;i=nxt[i])if(v[i]!=f[x]){
f[v[i]]=x,d[v[i]]=d[x]+1;
dfs(v[i]);
size[x]+=size[v[i]];
if(size[v[i]]>size[son[x]])son[x]=v[i];
}
}
void dfs2(int x,int y){
st[x]=++dfn;top[x]=y;
if(son[x])dfs2(son[x],y);
for(int i=g[x];i;i=nxt[i])if(v[i]!=son[x]&&v[i]!=f[x])dfs2(v[i],v[i]);
en[x]=dfn;
}
inline int lca2(int x,int y){
int t;
while(top[x]!=top[y])t=top[y],y=f[top[y]];
return x==y?t:son[x];
}
inline int ask(int x){
if(root==x)return n;
if(st[x]>st[root]||en[x]<en[root])return size[x];
return n-size[lca2(x,root)];
}
void check(int x){
if(x<1||x>n)exit(0);
}
int main(){
scanf("%d",&T);
for(C=1;C<=T;C++){
printf("Case #%d:\n",C);
scanf("%d%d%d",&n,&m,&root);
check(root);
for(ed=dfn=0,i=1;i<=n;i++)g[i]=0;
for(i=1;i<=n;i++)size[i]=son[i]=top[i]=f[i]=d[i]=0;
for(i=1;i<n;i++){
//x=i+1;y=rand()%i
scanf("%d%d",&x,&y);
check(x);
check(y);
add(x,y),add(y,x);
}
dfs(1);
dfs2(1,1);
while(m--){
scanf("%d%d",&x,&y);
check(y);
if(x==0)root=y;
else{
printf("%d\n",ask(y));
}
}
}
}

  

J. Printing Press

留坑。

K. Expected Number of Connected Components

留坑。

L. Coordinates

建树DFS即可确定出每个点的坐标。

#include<cstdio>
#include<algorithm>
using namespace std;
typedef long long ll;
const int N=100010,M=2000010;
const ll inf=1LL<<60;
int n,m,i,f[N],g[N],v[M],wx[M],wy[M],nxt[M],ed;
ll minx,miny,basex[N],basey[N],xx[N],yy[N];
inline void add(int x,int y,int dx,int dy){
v[++ed]=y;
wx[ed]=dx;
wy[ed]=dy;
nxt[ed]=g[x];
g[x]=ed;
}
void dfs(int x,int y,ll X,ll Y){
if(f[x])return;
f[x]=y;
xx[x]=X;
yy[x]=Y;
minx=min(minx,X);
miny=min(miny,Y);
for(int i=g[x];i;i=nxt[i])dfs(v[i],y,X+wx[i],Y+wy[i]);
}
int main(){
scanf("%d%d",&n,&m);
while(m--){
int x,y,dx,dy;
scanf("%d%d%d%d",&x,&y,&dx,&dy);
add(x,y,dx,dy);
add(y,x,-dx,-dy);
}
for(i=1;i<=n;i++)if(!f[i]){
minx=inf;
miny=inf;
dfs(i,i,0,0);
basex[i]=-minx;
basey[i]=-miny;
}
for(i=1;i<=n;i++)printf("%I64d %I64d\n",xx[i]+basex[f[i]],yy[i]+basey[f[i]]);
}

总结:

  • I题发现模板有误。
04-14 04:20