看到了题目之后知道自己可能做过两道,一道是弱化版,一道好像有感觉
可是就是想不到该怎么做,也就是说,我根本就记不住自己做过的题,啊,好伤心
然后想要自己且掉......毫无疑问失败了,于是悲观的认为别人都切了我要垫底了
第一题,我想到了是网络流,却是需要跑Q遍,并且没有正确性,能有暴力分也是奇迹
第二题,认为异常的熟悉,式子化到最后了,但是不会求了,写了个40就走了,然而最后交的时候忘记freopen了☺
第三题,卡常卡到家了,写了个莫队还没分......
可以看出是最小路径覆盖,也就是用最小权的路径覆盖所有的点
然而这里还有几个限制,可以合并,变成一条边覆盖终点不覆盖起点
这样每次费用流只增广一个点,并且花费是递增的,于是可以二分了
注意连边连的是最短路,因为有可能一个点经过两次,这样的情况在网络流中是无法表示的
所以我们用最短路,表示直接跨越那个点......
#include<bits/stdc++.h> using namespace std; #define fo(i,x,y) for(int i=(x);i<=(y);i++) #define fu(i,x,y) for(int i=(x);i>=(y);i--) int read(){ int s=0,t=1;char ch=getchar(); while(!isdigit(ch)){if(ch=='-')t=-1;ch=getchar();} while(isdigit(ch)){s=s*10+ch-'0';ch=getchar();} return s*t; } const int N=1005; const int M=1e6+5; const int inf=0x3f3f3f3f; int n,m,Q,C,s=501,t=502; int d[N][N]; struct E{int to,nxt,val,cot;}e[M*2]; int head[N],rp; void add_edg(int x,int y,int z,int w){ e[++rp].to=y;e[rp].nxt=head[x]; e[rp].val=z;e[rp].cot=w;head[x]=rp; } int dis[N],pre[N],epr[N],flo[N]; bool vis[N]; bool spfa(){ memset(dis,0x3f,sizeof(dis)); queue<int> q;while(!q.empty())q.pop(); q.push(s);dis[s]=0;flo[s]=inf; while(!q.empty()){ int x=q.front();q.pop();vis[x]=false; for(int i=head[x];i;i=e[i].nxt){ int y=e[i].to; if(!e[i].val||dis[y]<=dis[x]+e[i].cot)continue; dis[y]=dis[x]+e[i].cot; flo[y]=min(e[i].val,flo[x]); epr[y]=i;pre[y]=x; if(!vis[y])q.push(y),vis[y]=true; } } return (dis[t]!=inf); } int ji[N],cj,sum,cst[N]; void sol(){ int sum=0;memset(head,0,sizeof(head));rp=1; fo(i,1,n){ add_edg(s,i,1,0);add_edg(i,s,0,0); add_edg(i+n,t,1,0);add_edg(t,i+n,0,0); } fo(i,1,n)fo(j,1,n){ add_edg(i,j+n,inf,d[i][j]); add_edg(j+n,i,0,-d[i][j]); } while(spfa()){ int now=t;sum+=flo[t]; ji[sum]=dis[t]; cst[sum]=cst[sum-1]+dis[t]; while(now!=s){ e[epr[now]].val-=flo[t]; e[epr[now]^1].val+=flo[t]; now=pre[now]; } } } signed main(){ freopen("a.in","r",stdin); freopen("a.out","w",stdout); n=read();m=read();Q=read(); fo(i,1,n)fo(j,1,n)d[i][j]=100000; fo(i,1,m){ int x=read(),y=read(),z=read(); d[x][y]=min(d[x][y],z); } fo(k,1,n)fo(i,1,n)fo(j,1,n)d[i][j]=min(d[i][j],d[i][k]+d[k][j]); sol(); while(Q--){ C=read();int pos=lower_bound(ji+1,ji+n+1,C)-ji; printf("%d\n",cst[pos-1]+(n-pos+1)*C); } return 0; }
就不写式子了,挺好推的
最后分治一下,对n的范围分治
#include<bits/stdc++.h> using namespace std; #define fo(i,x,y) for(int i=(x);i<=(y);i++) #define fu(i,x,y) for(int i=(x);i>=(y);i--) int read(){ int s=0,t=1;char ch=getchar(); while(!isdigit(ch)){if(ch=='-')t=-1;ch=getchar();} while(isdigit(ch)){s=s*10+ch-'0';ch=getchar();} return s*t; } const int N=1e5+5; const int bas=20; const int mod=998244353; int ksm(int x,int y){ int ret=1; while(y){ if(y&1)ret=1ll*ret*x%mod; x=1ll*x*x%mod;y>>=1; }return ret; } int T,n,m,ans; int p[N],cnt,phi[N],mu[N]; bool vis[N]; int f[N],iph[N]; vector<int> sn[N],s[bas+1][bas+1]; void init(){ phi[1]=iph[1]=mu[1]=1; fo(i,2,100000){ if(!vis[i])p[++cnt]=i,phi[i]=i-1,mu[i]=-1; for(int j=1;j<=cnt&&i*p[j]<=100000;j++){ vis[i*p[j]]=true; if(i%p[j]==0){phi[i*p[j]]=phi[i]*p[j];mu[i*p[j]]=0;break;} else phi[i*p[j]]=phi[i]*(p[j]-1),mu[i*p[j]]=-mu[i]; } iph[i]=1ll*i*ksm(phi[i],mod-2)%mod; } fo(i,1,100000){ int now=0;sn[i].push_back(0); for(int j=i;j<=100000;j+=i){ f[j]=(f[j]+1ll*iph[i]*mu[j/i]+mod)%mod; now=(now+phi[j])%mod;sn[i].push_back(now); } } fo(j,1,bas)fo(k,1,bas){ int len=100000/max(j,k);s[j][k].resize(len+1); fo(i,1,len)s[j][k][i]=(s[j][k][i-1]+1ll*sn[i][j]*sn[i][k]%mod*f[i])%mod; } } signed main(){ freopen("b.in","r",stdin); freopen("b.out","w",stdout); //cerr<<(sizeof(s)>>20)<<endl; T=read();init(); cerr<<(sizeof(s)+sizeof(sn)>>20)<<endl; while(T--){ans=0; n=read();m=read(); for(int l=1,r;l<=min(n,m);l=r+1){ r=min(n/(n/l),m/(m/l)); if(max(n/l,m/l)>bas)fo(i,l,r)ans=(ans+1ll*sn[i][n/i]*sn[i][m/i]%mod*f[i]%mod)%mod; else ans=(ans+1ll*(s[n/l][m/l][r]-s[n/l][m/l][l-1]+mod))%mod; } printf("%d\n",ans); } return 0; }
考场上沉迷于log做法无法自拔......
根号的话,一切皆可预处理,于是很好做了
#include<bits/stdc++.h> using namespace std; #define ll long long #define fo(i,x,y) for(int i=(x);i<=(y);i++) #define fu(i,x,y) for(int i=(x);i>=(y);i--) inline ll read(){ ll s=0,t=1;char ch=getchar(); while(!isdigit(ch)){if(ch=='-')t=-1;ch=getchar();} while(isdigit(ch)){s=s*10+(ch^48);ch=getchar();} return s*t; } const int N=1e5+5; const int SQ=600; int n,m,typ,a[N];ll ans; struct BIT{ int tr[N]; inline void ins(int x,int v){for(int i=x;i<=n;i+=(i&-i))tr[i]+=v;} inline int query(int x){int ret=0;for(int i=x;i;i-=(i&-i))ret+=tr[i];return ret;} inline void clear(int x){for(int i=x;i<=n;i+=(i&-i)){if(!tr[i])break;tr[i]=0;}}; }bit; struct DIT{ int tr[N]; inline void ins(int x,int v){for(int i=x;i;i-=(i&-i))tr[i]+=v;} inline int query(int x){int ret=0;for(int i=x;i<=n;i+=(i&-i))ret+=tr[i];return ret;} inline void clear(int x){for(int i=x;i;i-=(i&-i)){if(!tr[i])break;tr[i]=0;}}; }dit; int bl[N],sq,le[SQ][N],sm[SQ][N],su[SQ]; int lv[N],rv[N]; signed main(){ freopen("c.in","r",stdin); freopen("c.out","w",stdout); n=read();m=read();typ=read();sq=pow(n,0.45); cerr<<sq<<endl; fo(i,1,n)a[i]=read(),bl[i]=(i-1)/sq+1; fo(i,1,bl[n]){ fo(j,(i-1)*sq+1,min(i*sq,n))le[i][a[j]]++; fo(j,1,n)le[i][j]+=le[i][j-1]; fo(j,1,(i-1)*sq)sm[i][j]=sm[i][j-1]+le[i][a[j]]; fo(j,(i-1)*sq+1,min(i*sq,n))sm[i][j]=sm[i][j-1]; fo(j,i*sq+1,n)sm[i][j]=sm[i][j-1]+(sq-le[i][a[j]]); fu(j,min(i*sq,n),(i-1)*sq+1)su[i]+=bit.query(a[j]),bit.ins(a[j],1),rv[j]=su[i]; fo(j,(i-1)*sq+1,min(n,i*sq))bit.clear(a[j]); dit.ins(a[(i-1)*sq+1],1);fo(j,(i-1)*sq+2,min(i*sq,n))lv[j]=lv[j-1]+dit.query(a[j]),dit.ins(a[j],1); fo(j,(i-1)*sq+1,min(i*sq,n))dit.clear(a[j]); } cerr<<(1.0*clock()/CLOCKS_PER_SEC)<<endl; while(m--){ int l=read()^(ans*typ),r=read()^(ans*typ);ans=0; if(bl[l]==bl[r]){ fu(i,r,l)ans+=bit.query(a[i]),bit.ins(a[i],1); fo(i,l,r)bit.clear(a[i]);printf("%lld\n",ans); continue; } fo(i,bl[l]+1,bl[r]-1){ ans+=su[i]; ans+=sm[i][(i-1)*sq]-sm[i][l-1]; ans+=sm[i][r]-sm[i][(bl[r]-1)*sq]; }ans+=rv[l]+lv[r]; fu(i,r,(bl[r]-1)*sq+1)bit.ins(a[i],1); fu(i,bl[l]*sq,l)ans+=bit.query(a[i]); fu(i,r,(bl[r]-1)*sq+1)bit.clear(a[i]); printf("%lld\n",ans); } return 0; }