我好像没什么长进啊
D0
和去年一样在浪
D1
T1一眼不可做,两眼傻逼题?裴蜀定理推一推就是a(b-1)-b
T2大模拟
T3先判零环的情况,然后令
fi,j
表示到第
i
个点,当前距离为
重构一张图,如果
表示度数数组没有清空,被卡了30分啊啊啊啊啊啊啊啊!!!
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
#include <string>
#include <queue>
using namespace std;
typedef pair<int,int> par;
const int N=100010,inf=1<<30;
inline char nc(){
static char buf[100000],*p1=buf,*p2=buf;
return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;
}
inline void rea(int &x){
char c=nc(); x=0;
for(;c>'9'||c<'0';c=nc());for(;c>='0'&&c<='9';x=x*10+c-'0',c=nc());
}
int t,n,m,k,p,cnt,G[N];
struct iedge{
int t,nx,w;
}E[N<<2],iE[N<<2];
int iG[N],icnt,rG[N];
void iclear(){
memset(iG,0,sizeof(iG)); icnt=0;
memset(G,0,sizeof(G)); cnt=0;
memset(rG,0,sizeof(rG));
}
inline void addedge(int x,int y,int z){
E[++cnt].t=y; E[cnt].nx=G[x]; E[cnt].w=z; G[x]=cnt;
E[++cnt].t=x; E[cnt].nx=rG[y]; rG[y]=cnt; E[cnt].w=z;
}
inline void iaddedge(int x,int y){
iE[++icnt].t=y; iE[icnt].nx=iG[x]; iG[x]=icnt;
}
int dis[N],rdis[N],du[N];
priority_queue<par> Q;
inline void dij(int s,int *cG,int *cdis){
for(int i=1;i<=n;i++) cdis[i]=inf;
cdis[s]=0; Q.push(par(0,s));
while(!Q.empty()){
int x=Q.top().second,y=-Q.top().first; Q.pop();
if(y!=cdis[x]) continue;
for(int i=cG[x];i;i=E[i].nx)
if(cdis[E[i].t]>cdis[x]+E[i].w){
cdis[E[i].t]=cdis[x]+E[i].w;
Q.push(par(-cdis[E[i].t],E[i].t));
}
}
}
int vis[N],low[N],dfn[N],sta[N],tp,tms,imx;
void tarjan(int x){
low[x]=dfn[x]=++tms;
vis[x]=1; sta[++tp]=x;
for(int i=iG[x];i;i=iE[i].nx){
if(!vis[iE[i].t]) tarjan(iE[i].t);
if(vis[iE[i].t]==1) low[x]=min(low[x],low[iE[i].t]);
}
if(low[x]==dfn[x]){
int cura=inf,curb=inf,cur,ccnt=0;
while(1){
cur=sta[tp--]; vis[cur]=2;
ccnt++;
cura=min(cura,dis[cur]); curb=min(curb,rdis[cur]);
if(cur==x || !tp) break;
}
if(ccnt>1)
imx=min(imx,cura+curb);
}
}
inline bool nooo(){
dij(n,rG,rdis);
for(int i=1;i<=n;i++) vis[i]=low[i]=dfn[i]=0;
tms=tp=0; imx=inf;
for(int i=1;i<=n;i++)
if(!vis[i]) tarjan(i);
return imx<=dis[n]+k;
}
int f[N][55];
int q[N],l,r;
int main(){
rea(t);
while(t--){
iclear();
rea(n); rea(m); rea(k); rea(p);
for(int i=1,x,y,z;i<=m;i++){
rea(x); rea(y); rea(z); addedge(x,y,z);
if(z==0) iaddedge(x,y);
}
dij(1,G,dis);
if(nooo()){
puts("-1"); continue;
}
for(int i=1;i<=n;i++)
for(int j=0;j<=k;j++){
if(dis[i]+j+rdis[i]>dis[n]+k) break;
f[i][j]=0;
}
for(int i=1;i<=n;i++) du[i]=0;
for(int x=1;x<=n;x++)
for(int i=G[x];i;i=E[i].nx)
if(dis[E[i].t]==dis[x]+E[i].w) du[E[i].t]++;
l=1; r=0;
q[r=1]=1;
while(l<=r){
int x=q[l++];
for(int i=G[x];i;i=E[i].nx)
if(dis[E[i].t]==dis[x]+E[i].w){
du[E[i].t]--;
if(!du[E[i].t]) q[++r]=E[i].t;
}
}
f[1][0]=1;
for(int j=0;j<=k;j++){
for(int ii=1;ii<=r;ii++){
int x=q[ii];
int cur=f[x][j];
if(!cur || dis[x]+j+rdis[x]>dis[n]+k) continue;
for(int i=G[x];i;i=E[i].nx){
int dd=dis[x]+j+E[i].w-dis[E[i].t];
if(dd<=k) f[E[i].t][dd]=(f[E[i].t][dd]+f[x][j])%p;
}
}
}
int ans=0;
for(int i=0;i<=k;i++) ans=(ans+f[n][i])%p;
printf("%d\n",ans);
}
return 0;
}
D1就这样吧…
D2
T1并查集送分
T2好像写了个三进制的状压DP,复杂度是
O(4n)
按层DP,
fi,S
令三进制状态
S
中,为0的位置表示这个点不在前
数组开小-10
#include <cstdio>
#include <iostream>
#include <algorithm>
using namespace std;
int n,m;
int lk[15][15],pw[15],val[15];
int f[15][531445];
int ttt[531445],lst[4150],ttt1[4150],sz[531445];
inline int iinn(int x,int y){
return (x/pw[y-1])%3;
}
inline int cst(int S){
int ret=0;
for(;S;S-=(1<<(lst[S]-1))){
if(val[lst[S]]==(1<<30)) return 1<<30;
ret+=val[lst[S]];
}
return ret;
}
int main(){
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++) lk[i][j]=1<<30;
for(int i=1,x,y,z;i<=m;i++){
scanf("%d%d%d",&x,&y,&z);
lk[x][y]=lk[y][x]=min(lk[x][y],z);
}
pw[0]=1; for(int i=1;i<=n;i++) pw[i]=3*pw[i-1];
for(int i=1;i<=n;i++)
for(int j=0;j<pw[n];j++) f[i][j]=1<<30;
for(int i=0;i<pw[n];i++)
for(int j=1;j<=n;j++)
if(!iinn(i,j)) ttt[i]|=1<<(j-1);
else sz[i]++;
for(int i=1;i<(1<<n);i++)
for(int j=1;j<=n;j++)
if((i>>(j-1))&1) ttt1[i]+=pw[j-1]*2;
lst[1]=1;
for(int i=2;i<(1<<n);i++)
lst[i]=lst[i>>1]+1;
for(int i=1;i<=n;i++) f[1][pw[i-1]*2]=0;
int ans=1<<30;
for(int i=1;i<=n;i++)
for(int S=0;S<pw[n];S++){
if(f[i][S]>=ans) continue;
if(sz[S]==n) ans=min(ans,f[i][S]);
for(int j=1;j<=n;j++)
if(!iinn(S,j)){
val[j]=1<<30;
for(int k=1;k<=n;k++)
if(iinn(S,k)==2) val[j]=min(val[j],lk[k][j]);
}
int nxt=0,SS=ttt[S];
for(int j=1;j<=n;j++)
if(iinn(S,j)) nxt+=pw[j-1];
for(int ss=SS;ss;ss=(ss-1)&SS){
int cur=cst(ss);
if(cur==(1<<30)) continue;
f[i+1][nxt+ttt1[ss]]=min(f[i+1][nxt+ttt1[ss]],f[i][S]+cur*i);
}
}
printf("%d\n",ans);
return 0;
}
T3我是个傻逼啊
暴力打挂,没开longlong,-30
大力平衡树模拟就好了…
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstdlib>
#define fi first
#define se second
using namespace std;
typedef long long ll;
const int N=2000010;
struct node{
node *ls,*rs;
int x,y,val,size,key,tag;
}pool[N],*t;
int n,m,q;
inline char nc(){
static char buf[100000],*p1=buf,*p2=buf;
return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;
}
inline void read(int &x){
char c=nc(); x=0;
for(;c>'9'||c<'0';c=nc());for(;c>='0'&&c<='9';x=x*10+c-'0',c=nc());
}
node *ro[N],*L;
inline node *crt(int x,int y,int k,int v){
node *ret=t++;
ret->x=x; ret->y=y; ret->val=v; ret->key=k;
return ret;
}
inline void Up(node *x){
x->size=(x->ls?x->ls->size:0)+(x->rs?x->rs->size:0)+1;
}
inline void Push(node *x){
if(!x->tag) return ;
if(x->ls)
x->ls->tag+=x->tag,x->ls->key+=x->tag;
if(x->rs)
x->rs->tag+=x->tag,x->rs->key+=x->tag;
x->tag=0;
}
inline node *Merge(node *x,node *y){
if(!x || !y) return x?x:y;
Push(x); Push(y);
if(x->val>y->val){
x->rs=Merge(x->rs,y); Up(x); return x;
}
else{
y->ls=Merge(x,y->ls); Up(y); return y;
}
}
void PutAns(ll x){
if(x>=10) PutAns(x/10);
putchar(x%10+'0');
}
typedef pair<node*,node*> Dnode;
Dnode Split(node *cur,int x){
if(!cur) return Dnode(NULL,NULL);
Push(cur); Dnode ret;
if(cur->key<x){
ret=Split(cur->rs,x);
cur->rs=ret.fi; ret.fi=cur;
}
else{
ret=Split(cur->ls,x);
cur->ls=ret.se; ret.se=cur;
}
Up(cur); return ret;
}
inline node *lst(node *cur){
while(cur->rs) cur=cur->rs;
return cur;
}
inline node *fst(node *cur){
while(cur->ls) cur=cur->ls;
return cur;
}
int main(){
t=pool;
read(n); read(m); read(q);
for(int i=1;i<=n;i++)
L=Merge(L,crt(i,m,i,rand()));
for(int i=1;i<=n;i++)
ro[i]=Merge(ro[i],crt(i,1,1,rand()));
while(q--){
int x,y;
read(x); read(y);
if(y==m){
Dnode A=Split(L,x),B=Split(A.se,x+1);
PutAns(1LL*(B.fi->x-1)*m+B.fi->y); putchar('\n');
B.fi->key=n; if(B.se) B.se->tag-=1,B.se->key-=1;
L=Merge(A.fi,Merge(B.se,B.fi));
}
else{
Dnode A=Split(ro[x],y),B=Split(A.se,y+1);
node *cur;
if(B.fi) cur=B.fi; else cur=lst(A.fi);
PutAns(1LL*(cur->x-1)*m+cur->y+y-cur->key); putchar('\n');
if((!B.se || fst(B.se)->key!=y+1) && y+1!=m)
B.se=Merge(crt(cur->x,cur->y+y-cur->key+1,y+1,rand()),B.se);
if(B.se) B.se->tag-=1,B.se->key-=1;
ro[x]=Merge(A.fi,B.se);
Dnode C=Split(L,x),D=Split(C.se,x+1);
D.fi->key=m-1; if(D.se) D.se->tag-=1,D.se->key-=1;
ro[x]=Merge(ro[x],D.fi);
if(cur->key==y)
cur->key=n,L=Merge(C.fi,Merge(D.se,cur));
else
L=Merge(C.fi,Merge(D.se,crt(cur->x,cur->y+y-cur->key,n,rand())));
}
}
return 0;
}
分数跟去年一样490
D1T3+D2T2+D2T3=30+10+30=70
因为自己傻逼少了70分
怕是要退役了