(A)
咕咕咕
const int N=1e6+5;
char s[N],t[N];int n,res;
inline bool cmp(const int &x,const int &y){return x>y;}
int main(){
scanf("%s",s+1),n=strlen(s+1);
fp(i,1,n)t[i]=s[i];sort(t+1,t+1+n,cmp);
fp(i,1,n)res=(res*10+t[i]-s[i]),res=(res%10+10)%10;
printf("%d
",res);
return 0;
}
(B)
先预处理出(dp[i])表示花费(i)的代价最多能在(n)天之后获得的回报,然后直接(dp)就行了
//quming
#include<bits/stdc++.h>
#define R register
#define fp(i,a,b) for(R int i=(a),I=(b)+1;i<I;++i)
#define fd(i,a,b) for(R int i=(a),I=(b)-1;i>I;--i)
#define go(u) for(int i=head[u],v=e[i].v;i;i=e[i].nx,v=e[i].v)
template<class T>inline bool cmax(T&a,const T&b){return a<b?a=b,1:0;}
template<class T>inline bool cmin(T&a,const T&b){return a>b?a=b,1:0;}
using namespace std;
typedef long long ll;
const int N=10005;
ll dp[N],f[2][N],res;int w[N],n,m,k,t;
inline int calc(R int x){return x<=k?w[x]:0;}
int main(){
scanf("%d%d%d",&n,&m,&k);
fp(i,0,k)scanf("%d",&w[i]);
memset(dp,0xef,sizeof(dp)),dp[0]=0;
for(R int a,b;m;--m){
scanf("%d%d",&a,&b);
fp(i,a,2000)if(dp[i-a]>=0)cmax(dp[i],dp[i-a]+b);
}
memset(f[0],0xef,sizeof(f[0])),f[t=0][calc(0)]=0;
fp(i,1,n-1){
memset(f[t^1],0xef,sizeof(f[t^1]));
fp(j,0,2000)if(f[t][j]>=0){
// printf("%d %d %lld
",i,j,f[t][j]);
fp(l,0,j)
cmax(f[t^1][j-l+calc(j-l)],f[t][j]+dp[l]);
}
t^=1;
}
res=-1e18;
fp(i,0,2000)if(f[t][i]>=0)cmax(res,f[t][i]+i);
printf("%lld
",res);
return 0;
}
(C)
我觉得应该只有我一个人是(zz)到写了个(O(nlog n))的大常数做法结果居然跑过去了的人……
做法一
首先一段的长度显然不能超过({(n-1)over 2})。先破环成链,我们记(las_i)表示以(i)为结尾,最小的(j)满足([j+1,i])是一个合法的区间,同理定义(nxt_i)表示最大的(j)满足([i,j-1])是一个是一个合法的区间
我们枚举其中一个区间的末尾,那么最终得到的答案除以(3)就是原来的答案了
假设末尾为(t),那么这个环的开头就是(s=t-n+1),我们需要数的就是满足(iin[las_j,j-1],iin [s,nxt_s-1],jin [las_t,i-1])的数对(i,j)的个数
我们可以把每个(j)看做一个对于([las_j,j-1])的区间加,用个指针保证只有(jin [las_t,i-1])的区间有贡献,然后区间查询([s,nxt_s-1])就可以了。一开始用线段树似乎(MLE)了,后来改成树状数组结果卡了半天的常最后(955ms)过了此题……
做法二
不破环成链了,定义稍微改一改,记(las_i)表示以(i-1)为结尾的最小的(j)满足([j,i])是一个合法的区间(只考虑(j>i)的那些,也就是说这个区间实际上是([j,n]|[1,i-1])),以及(nxt_i)表示最大的(j)满足([i,j])是个合法的区间
我们枚举(a,b),则需要满足的条件是(bin [a+1,nxt_a+1],cin [b+1,nxt_b+1],cin[las_a,n])
为了方便起见我们把所有(nxt_b>n-1)的都设为(n-1),可以看出不会影响答案
因为每一个区间的长度都小于等于({(n-1)over 2}),所以(b<las_a)恒成立,那么(c)的合法的取值方案就是(nxt_b+2-las_a)
那么我们枚举(a),用双指针维护所有合法的(b)的贡献即可
具体细节可以参考代码
代码一
//quming
#include<bits/stdc++.h>
#define R register
#define fp(i,a,b) for(R int i=(a),I=(b)+1;i<I;++i)
#define fd(i,a,b) for(R int i=(a),I=(b)-1;i>I;--i)
#define go(u) for(int i=head[u],v=e[i].v;i;i=e[i].nx,v=e[i].v)
template<class T>inline bool cmax(T&a,const T&b){return a<b?a=b,1:0;}
template<class T>inline bool cmin(T&a,const T&b){return a>b?a=b,1:0;}
typedef long long ll;
char buf[1<<21],*p1=buf,*p2=buf;
inline char getc(){return p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++;}
int read(){
R int res,f=1;R char ch;
while((ch=getc())>'9'||ch<'0')(ch=='-')&&(f=-1);
for(res=ch-'0';(ch=getc())>='0'&&ch<='9';res=res*10+ch-'0');
return res*f;
}
const int N=4e6+5;
ll d[N];int c[N];
int a[N],las[N],nxt[N],pos[N],n,m,len;ll res;
inline int max(R int x,R int y){return x>y?x:y;}
inline int min(R int x,R int y){return x<y?x:y;}
inline void chgd(R int x,R int v){for(;x<=m;x+=x&-x)d[x]+=v;}
inline void chgc(R int x,R int v){for(;x<=m;x+=x&-x)c[x]+=v;}
inline void upd(R int l,R int r,R int v){
chgc(r+1,-v),chgd(r+1,-v*(r+1));
if(l!=0)chgc(l,v),chgd(l,v*l);
}
inline int askc(R int x){R int res=0;for(;x;x-=x&-x)res+=c[x];return res;}
inline ll askd(R int x){R ll res=0;for(;x;x-=x&-x)res+=d[x];return res;}
inline ll query(R int l,R int r){
R ll res=0;
res+=1ll*(r+1)*askc(r)-askd(r);
if(l>1)res-=1ll*l*askc(l-1)-askd(l-1);
return res;
}
int main(){
// freopen("testdata.in","r",stdin);
n=read(),m=n<<1;
fp(i,1,n)a[i]=read(),a[n+i]=a[i];
len=(n-1)>>1;
las[0]=0,nxt[n<<1|1]=(n<<1|1);
fp(i,1,n<<1)las[i]=max(las[i-1],max(i-len,pos[a[i]])),pos[a[i]]=i;
fp(i,1,n)pos[i]=(n<<1|1);
fd(i,n<<1,1)nxt[i]=min(nxt[i+1],min(i+len,pos[a[i]])),pos[a[i]]=i;
// fp(i,2,n)upd(las[i],i-1,1);
fp(i,las[n+1],n)upd(las[i],i-1,1);
for(R int i=n+1,j=las[n+1];i<=(n<<1);++i){
while(j<las[i])upd(las[j],j-1,-1),++j;
res+=query(i-n+1,nxt[i-n+1]-1);
upd(las[i],i-1,1);
}
printf("%lld
",res/3);
return 0;
}
代码二
//minamoto
#include<bits/stdc++.h>
#define R register
#define fp(i,a,b) for(R int i=(a),I=(b)+1;i<I;++i)
#define fd(i,a,b) for(R int i=(a),I=(b)-1;i>I;--i)
#define go(u) for(int i=head[u],v=e[i].v;i;i=e[i].nx,v=e[i].v)
template<class T>inline bool cmax(T&a,const T&b){return a<b?a=b,1:0;}
template<class T>inline bool cmin(T&a,const T&b){return a>b?a=b,1:0;}
typedef long long ll;
char buf[1<<21],*p1=buf,*p2=buf;
inline char getc(){return p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++;}
int read(){
R int res,f=1;R char ch;
while((ch=getc())>'9'||ch<'0')(ch=='-')&&(f=-1);
for(res=ch-'0';(ch=getc())>='0'&&ch<='9';res=res*10+ch-'0');
return res*f;
}
const int N=4e6+5;
int a[N],las[N],nxt[N],pos[N],c[N],n,m,len,cnt;ll res,sum;
inline int max(R int x,R int y){return x>y?x:y;}
inline int min(R int x,R int y){return x<y?x:y;}
int main(){
// freopen("testdata.in","r",stdin);
n=read(),len=(n-1)>>1;
fp(i,1,n)a[i]=read(),a[n+i]=a[i];
las[0]=0,nxt[n<<1|1]=(n<<1|1);
fp(i,1,n<<1)las[i]=max(las[i-1],max(i-len+1,pos[a[i]]+1)),pos[a[i]]=i;
fp(i,1,n)pos[i]=(n<<1|1);
fd(i,n<<1,1)nxt[i]=min(nxt[i+1],min(i+len-1,pos[a[i]]-1)),pos[a[i]]=i;
fp(i,1,n)las[i]=las[i+n-1],cmin(nxt[i],n-1);
/*
fp(i,1,n)if(las[i]>i){
fp(j,i+1,nxt[i]+1)if(nxt[j]+1>=las[i])res+=nxt[j]+2-las[i];
}else break;
*/
for(R int i=1,j=1,l=1,r=1;i<=n;++i){
if(las[i]<=i)break;
while(r<=nxt[i]+1)++cnt,++c[nxt[r]+1],sum+=nxt[r]+2,++r;
while(l<r&&(l<=i||nxt[l]+1<las[i]))--cnt,--c[nxt[l]+1],sum-=nxt[l]+2,++l;
res+=sum-1ll*cnt*las[i];
}
printf("%lld
",res);
return 0;
}
(D)
类似于(kruskal)重构树的过程,我们从小到大枚举点,且只考虑那些从大连向小的边。对于新建出的这棵树,我们要保证每个点都小于其父亲节点,所以对于当前点枚举所有出边,把对应的连通块接到当前点的子树里就行了
那么这就是一个类似于(kruskal)重构树的东西了,询问的时候倍增(+)线段树就行了
//quming
#include<bits/stdc++.h>
#define R register
#define pb emplace_back
#define fp(i,a,b) for(R int i=(a),I=(b)+1;i<I;++i)
#define fd(i,a,b) for(R int i=(a),I=(b)-1;i>I;--i)
#define go(u) for(int i=head[u],v=e[i].v;i;i=e[i].nx,v=e[i].v)
template<class T>inline bool cmax(T&a,const T&b){return a<b?a=b,1:0;}
template<class T>inline bool cmin(T&a,const T&b){return a>b?a=b,1:0;}
using namespace std;
const int P=998244353;
inline void upd(R int &x,R int y){(x+=y)>=P?x-=P:0;}
inline int add(R int x,R int y){return x+y>=P?x+y-P:x+y;}
inline int dec(R int x,R int y){return x-y<0?x-y+P:x-y;}
inline int mul(R int x,R int y){return 1ll*x*y-1ll*x*y/P*P;}
int ksm(R int x,R int y){
R int res=1;
for(;y;y>>=1,x=mul(x,x))(y&1)?res=mul(res,x):0;
return res;
}
const int N=5e5+5;
vector<int>to[N];
struct eg{int v,nx;}e[N<<1];int head[N],tot;
inline void Add(R int u,R int v){e[++tot]={v,head[u]},head[u]=tot;}
int a[N],rk[N],dfn[N],low[N],fa[N][35],ga[N],dep[N],Log[N],tim,n,m,q;
inline int find(R int x){return ga[x]==x?x:ga[x]=find(ga[x]);}
struct node;typedef node* ptr;
struct node{
ptr lc,rc;int v;
inline void upd(){v=mul(lc->v,rc->v);}
}ee[N<<2],*pp=ee,*rt;
void build(ptr &p,int l,int r){
p=++pp;if(l==r)return p->v=a[rk[r]],void();
int mid=(l+r)>>1;
build(p->lc,l,mid),build(p->rc,mid+1,r);
p->upd();
}
void update(ptr p,int l,int r,int x,int v){
if(l==r)return p->v=v,void();
int mid=(l+r)>>1;
x<=mid?update(p->lc,l,mid,x,v):update(p->rc,mid+1,r,x,v);
p->upd();
}
int query(ptr p,int l,int r,int ql,int qr){
if(ql<=l&&qr>=r)return p->v;
int mid=(l+r)>>1,res=1;
if(ql<=mid)res=mul(res,query(p->lc,l,mid,ql,qr));
if(qr>mid)res=mul(res,query(p->rc,mid+1,r,ql,qr));
return res;
}
void dfs(int u,int f){
dfn[u]=++tim,rk[tim]=u,fa[u][0]=f;
fp(i,1,20)fa[u][i]=fa[fa[u][i-1]][i-1];
go(u)dfs(v,u);
low[u]=tim;
}
inline int jump(R int u,R int x){
if(u>x)return 0;
// R int k=dep[u];
fd(i,20,0)if(fa[u][i]&&fa[u][i]<=x)u=fa[u][i];
return query(rt,1,n,dfn[u],low[u]);
}
int main(){
// freopen("testdata.in","r",stdin);
scanf("%d%d%d",&n,&m,&q);
fp(i,1,n)scanf("%d",&a[i]),ga[i]=i,a[i]%=P;
for(R int i=1,u,v;i<=m;++i)scanf("%d%d",&u,&v),to[u].pb(v),to[v].pb(u);
fp(u,1,n)for(auto v:to[u])if(v<u&&u!=find(v))Add(u,find(v)),ga[find(v)]=u;
// fp(i,1,n)fa[i][0]=ga[i];
Log[0]=-1;fp(i,2,n)Log[i]=Log[i>>1]+1;
dfs(n,0);
build(rt,1,n);
for(int op,u,v;q;--q){
scanf("%d%d%d",&op,&u,&v);
if(op==1)printf("%d
",jump(u,v));
else update(rt,1,n,dfn[u],v%P);
}
return 0;
}
(E)
首先,如果造成的总伤害为(x),那么这些伤害是等价的,所以分配给(n)个人的方案数等价于用(n-1)个隔板插进(x-1)个空当中的方案数,再乘上造成(x)点伤害的方案数就是对应的贡献
我们设(F_i(x))的第(k)项表示对于第(i)个种族的一个生物,往里插(k)个隔板的总的贡献,那么答案就是([x^{n-1}]prod_{i=1}^m F_i^{a^i}(x))
然后考虑一个种族的生物的贡献是什么,分别设为(a,b),首先([x^0]F_i(i)=b),即不插隔板,则(i)选择造成的伤害总共有(b)种情况。如果把伤害看成一堆点,我们往中间插隔板,那么会发现两个生物连接起来的时候,我们还需要考虑连接处是否插隔板。那么对于插(k>0)个隔板的时候,我们默认最后一个点的后面那个位置也能插,所以贡献为
这样的话记得把最后一个生物给特判一下
因为多项式长度不超过(O(n)),所以总复杂度为(O(nmlog n)),当然直接暴力多项式快速幂也挺快就是了
//quming
#include<bits/stdc++.h>
#define R register
#define fp(i,a,b) for(R int i=(a),I=(b)+1;i<I;++i)
#define fd(i,a,b) for(R int i=(a),I=(b)-1;i>I;--i)
#define go(u) for(int i=head[u],v=e[i].v;i;i=e[i].nx,v=e[i].v)
using namespace std;
const int N=(1<<18)+5,P=998244353;
inline int add(R int x,R int y){return x+y>=P?x+y-P:x+y;}
inline int dec(R int x,R int y){return x-y<0?x-y+P:x-y;}
inline int mul(R int x,R int y){return 1ll*x*y-1ll*x*y/P*P;}
int ksm(R int x,R int y){
R int res=1;
for(;y;y>>=1,x=mul(x,x))(y&1)?res=mul(res,x):0;
return res;
}
int r[21][N],rt[2][N<<1],inv[N],lg[N],lim,d;
void init(){
fp(d,1,18){
fp(i,1,(1<<d)-1)r[d][i]=(r[d][i>>1]>>1)|((i&1)<<(d-1));
lg[1<<d]=d;
}
inv[0]=inv[1]=1;
fp(i,2,262144)inv[i]=mul(P-P/i,inv[P%i]);
for(R int t=(P-1)>>1,i=1,x,y;i<262144;i<<=1,t>>=1){
x=ksm(3,t),y=ksm(332748118,t),rt[0][i]=rt[1][i]=1;
fp(k,1,i-1)
rt[1][i+k]=mul(rt[1][i+k-1],x),
rt[0][i+k]=mul(rt[0][i+k-1],y);
}
}
void NTT(int *A,int ty){
fp(i,0,lim-1)if(i<r[d][i])swap(A[i],A[r[d][i]]);
for(R int mid=1;mid<lim;mid<<=1)
for(R int j=0,t;j<lim;j+=(mid<<1))
fp(k,0,mid-1)
A[j+k+mid]=dec(A[j+k],t=mul(rt[ty][mid+k],A[j+k+mid])),
A[j+k]=add(A[j+k],t);
if(!ty)fp(i,0,lim-1)A[i]=mul(A[i],inv[lim]);
}
void Mul(const int *a,const int *b,int *c,int len){
static int A[N],B[N];
lim=(len<<1),d=lg[lim];
fp(i,0,len-1)A[i]=a[i],B[i]=b[i];
fp(i,len,lim-1)A[i]=B[i]=0;
NTT(A,1),NTT(B,1);
fp(i,0,lim-1)A[i]=mul(A[i],B[i]);
NTT(A,0);
fp(i,0,len-1)c[i]=A[i];
fp(i,len,lim-1)c[i]=0;
}
void Inv(int *a,int *b,int len){
if(len==1)return b[0]=ksm(a[0],P-2),void();
Inv(a,b,len>>1);
static int A[N],B[N];lim=(len<<1),d=lg[lim];
fp(i,0,len-1)A[i]=a[i],B[i]=b[i];
fp(i,len,lim-1)A[i]=B[i]=0;
NTT(A,1),NTT(B,1);
fp(i,0,lim-1)A[i]=mul(A[i],mul(B[i],B[i]));
NTT(A,0);
fp(i,0,len-1)b[i]=dec(add(b[i],b[i]),A[i]);
fp(i,len,lim-1)b[i]=0;
}
void Ln(int *a,int *b,int len){
static int A[N],B[N];
fp(i,1,len-1)A[i-1]=mul(a[i],i);A[len-1]=0;
Inv(a,B,len);lim=(len<<1),d=lg[lim];
fp(i,len,lim-1)A[i]=B[i]=0;
NTT(A,1),NTT(B,1);
fp(i,0,lim-1)A[i]=mul(A[i],B[i]);
NTT(A,0);
fp(i,1,len-1)b[i]=mul(A[i-1],inv[i]);b[0]=0;
fp(i,len,lim-1)b[i]=0;
}
void Exp(int *a,int *b,int len){
if(len==1)return b[0]=1,void();
Exp(a,b,len>>1);
static int A[N];Ln(b,A,len);
lim=(len<<1),d=lg[lim];
A[0]=dec(a[0]+1,A[0]);
fp(i,1,len-1)A[i]=dec(a[i],A[i]);
fp(i,len,lim-1)A[i]=b[i]=0;
NTT(A,1),NTT(b,1);
fp(i,0,lim-1)b[i]=mul(A[i],b[i]);
NTT(b,0);
fp(i,len,lim-1)b[i]=0;
}
//inline void ksm(int *a,int *b,int len,int k){
// static int res[N],A[N];
// res[0]=1;fp(i,1,len-1)res[i]=0;
// fp(i,0,len-1)A[i]=a[i];
// for(;k;k>>=1,Mul(A,A,A,len))if(k&1)Mul(res,A,res,len);
// fp(i,0,len-1)b[i]=res[i];
//}
inline void ksm(int *a,int *b,int len,int k){
static int A[N];R int t=a[0],it=ksm(t,P-2);
t=ksm(t,k);
fp(i,0,len-1)a[i]=mul(a[i],it);
assert(a[0]==1);
Ln(a,A,len);
fp(i,0,len-1)A[i]=mul(A[i],k);
Exp(A,b,len);
fp(i,0,len-1)b[i]=mul(b[i],t);
}
int a[N],b[N],ans[N],f[N],g[N],n,m;
int main(){
// freopen("testdata.in","r",stdin);
scanf("%d%d",&n,&m),init();
fp(i,1,m)scanf("%d%d",&a[i],&b[i]);
++m,a[m]=1,b[m]=b[m-1]-1,--a[m-1];
R int len=1;while(len<n)len<<=1;
ans[0]=1;
fp(i,1,m)if(a[i]){
f[0]=b[i];R int t=b[i]+1;
fp(k,1,len-1){
t=mul(t,mul(inv[k+1],b[i]+1-k));
f[k]=t;
}
if(i==m)++f[0];
ksm(f,g,len,a[i]);
Mul(ans,g,ans,len);
}
printf("%d
",ans[n-1]);
return 0;
}
(F)
显然并没有搞懂子集卷积的实质啊……
首先(DAG)计数的套路就是容斥,即对于集合(S),我们枚举它的哪一个子集(T(T eq varnothing))出度为(0),然后乘个容斥系数就好了
记(es_S)表示集合(S)中的边数之和,即总的方案数是
发现这是一个子集卷积的形式,类似于集合并卷积的性质,我们发现如果把(f,g)都莫比乌斯变换之后系数等于对应项的点值之积,那么就可以(O(n^22^n))求出(f)了
具体细节可以看代码
//quming
#include<bits/stdc++.h>
#define R register
#define fp(i,a,b) for(R int i=(a),I=(b)+1;i<I;++i)
#define fd(i,a,b) for(R int i=(a),I=(b)-1;i>I;--i)
#define go(u) for(int i=head[u],v=e[i].v;i;i=e[i].nx,v=e[i].v)
template<class T>inline bool cmax(T&a,const T&b){return a<b?a=b,1:0;}
template<class T>inline bool cmin(T&a,const T&b){return a>b?a=b,1:0;}
using namespace std;
const int P=998244353,inv=499122177;
inline void upd(R int &x,R int y){(x+=y)>=P?x-=P:0;}
inline int add(R int x,R int y){return x+y>=P?x+y-P:x+y;}
inline int dec(R int x,R int y){return x-y<0?x-y+P:x-y;}
inline int mul(R int x,R int y){return 1ll*x*y-1ll*x*y/P*P;}
int ksm(R int x,R int y){
R int res=1;
for(;y;y>>=1,x=mul(x,x))(y&1)?res=mul(res,x):0;
return res;
}
const int N=25,L=(1<<20)+5;
int sz[L],es[L],f[N][L],g[N][L],Lg[L],bin[N*N],n,m,lim;
inline void fwt(int *a,int len){
for(R int i=1;i<len;i<<=1)
for(R int p=(i<<1),j=0;j<len;j+=p)
fp(k,0,i-1)upd(a[i+j+k],a[j+k]);
}
inline void ifwt(int *a,int len){
for(R int i=1;i<len;i<<=1)
for(R int p=(i<<1),j=0;j<len;j+=p)
fp(k,0,i-1)upd(a[i+j+k],P-a[j+k]);
}
int main(){
// freopen("testdata.in","r",stdin);
scanf("%d%d",&n,&m),lim=(1<<n);
fp(i,1,lim-1)sz[i]=sz[i>>1]+(i&1);
fp(i,0,n-1)Lg[1<<i]=i;
bin[0]=1;fp(i,1,n*n)bin[i]=mul(bin[i-1],inv);
for(R int i=1,u,v;i<=m;++i){
scanf("%d%d",&u,&v),--u,--v;
fp(s,0,lim-1)if((s>>u&1)&&(s>>v&1))++es[s];
}
fp(i,0,lim-1)g[sz[i]][i]=sz[i]&1?bin[es[i]]:P-bin[es[i]];
fp(i,0,n)fwt(g[i],lim);
f[0][0]=1,fwt(f[0],lim);
fp(i,1,n)fp(j,0,i-1)fp(k,0,lim-1)upd(f[i][k],mul(f[j][k],g[i-j][k]));
ifwt(f[n],lim);
printf("%d
",mul(f[n][lim-1],ksm(mul(2,ksm(3,P-2)),m)));
return 0;
}