NOIP2017解题报告
啊不小心点发布了,懒得删了就这样吧,虽然还没写完,也不打算写了大概。
d1t1
结论题 没什么好说的
d1t2
模拟 没什么好说的
d1t3
70分算法其实比较好想。
没有0边,就跑最短路,然后按dis从小到大转移。
场上最后十分钟才发现单向边,就没时间考虑0边,并且相当于傻逼一样排了个序,水了60;
肯定不能直接排序呀 n*k*log爆了啊,只把n个点按dis排序,然后先枚举一个k即可,肯定是从k小的转移到大的。
然后0边重新建图,拓扑排序,看环上有没有可行解,有就输出-1。否则把拓扑序作为第二关键字排序,转移即可。
//Achen
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<cstdio>
#include<vector>
#include<queue>
#include<ctime>
#include<cmath>
const int N=100005;
const int M=200005;
typedef long long LL;
using namespace std;
int T,n,m,k,p;
LL dp[N][51];
template<typename T> void read(T &x) {
char ch=getchar(); x=0; T f=1;
while(ch!='-'&&(ch<'0'||ch>'9')) ch=getchar();
if(ch=='-') f=-1,ch=getchar();
for(;ch>='0'&&ch<='9';ch=getchar()) x=x*10+ch-'0'; x*=f;
}
int fir[N],nxt[M],to[M],val[M],ecnt;
int fif[N],nxf[M],tf[M],vaf[M],ecnf;
void add(int u,int v,int w) {
nxt[++ecnt]=fir[u]; fir[u]=ecnt; to[ecnt]=v; val[ecnt]=w;
nxf[++ecnf]=fif[v]; fif[v]=ecnf; tf[ecnf]=u; vaf[ecnf]=w;
}
int fi[N],nx[M],tt[M],in[N],ec;
void Add(int u,int v) {
nx[++ec]=fi[u]; fi[u]=ec; tt[ec]=v; in[v]++;
}
queue<int>que;
int ds[N],dt[N],vis[N],tps[N];
void spfa(int s,int d[],int fir[],int nxt[],int to[],int val[]) {
d[s]=0;
vis[s]=1;
que.push(s);
while(!que.empty()) {
int x=que.front();
que.pop();
vis[x]=0;
for(int i=fir[x];i;i=nxt[i])
if(d[to[i]]>d[x]+val[i]) {
d[to[i]]=d[x]+val[i];
if(!vis[to[i]]) {
vis[to[i]]=1;
que.push(to[i]);
}
}
}
}
int tpsort() {
for(int i=1;i<=n;i++) if(!in[i]) que.push(i);
int idd=0;
while(!que.empty()) {
int x=que.front();
que.pop();
tps[x]=++idd;
for(int i=fi[x];i;i=nx[i]) {
if(!(--in[tt[i]]))
que.push(tt[i]);
}
}
for(int i=1;i<=n;i++)
if(in[i]&&ds[i]+dt[i]<=ds[n]+k)
return 1;
return 0;
}
struct node{
int x;
friend bool operator <(const node &A,const node &B) {
return ds[A.x]==ds[B.x]?tps[A.x]<tps[B.x]:ds[A.x]<ds[B.x];
}
}po[N*50];
void clear() {
ecnt=ec=ecnf=0;
memset(dt,127,sizeof(dt));
memset(ds,127,sizeof(ds));
memset(fi,0,sizeof(fir));
memset(fir,0,sizeof(fir));
memset(fif,0,sizeof(fif));
memset(in,0,sizeof(in));
memset(tps,0,sizeof(tps));
memset(dp,0,sizeof(dp));
}
void work() {
spfa(1,ds,fir,nxt,to,val);
spfa(n,dt,fif,nxf,tf,vaf);
if(tpsort()) printf("-1\n");
else {
int tot=0;
for(int i=1;i<=n;i++)
po[++tot].x=i;
dp[1][0]=1;
sort(po+1,po+tot+1);
for(int y=0;y<=k;y++) {
for(int o=1;o<=tot;o++) {
int x=po[o].x;
for(int i=fir[x];i;i=nxt[i])
if((LL)ds[x]+y+val[i]+dt[to[i]]<=ds[n]+k) {
(dp[to[i]][ds[x]+y+val[i]-ds[to[i]]]+=dp[x][y])%=p;
}
}
}
LL ans=0;
for(int i=0;i<=k;i++) (ans+=dp[n][i])%=p;
printf("%lld\n",ans);
}
}
void init() {
read(T);
while(T--) {
clear();
read(n);
read(m);
read(k);
read(p);
for(int i=1;i<=m;i++) {
int u,v,w;
read(u); read(v); read(w);
if(!w) Add(u,v);
add(u,v,w);
}
work();
}
}
#define DEBUG
int main() {
#ifdef DEBUG
freopen("park.in","r",stdin);
freopen("park.out","w",stdout);
#endif
init();
return 0;
}
d2t1
并查集
之前在长一考了一道有点像的二维的用并查集这样搞可以水80;
d2t2
一眼状压,然后不会。
推了半个小时prufer数列,并没有什么用。
自己对dp的理解还是太粗浅了。
一个可做的方法是,枚举层数,枚举状态,枚举补集,暴力转移。
你觉得十分不科学,然而事实是这样是可以得出正确答案的。
几个事。
1。不一定全部的状态或者转移都是最优的,只要最终可以达到最优解即可。
2。注意细节,如果层数枚举到12然后空间只开13你不就越界了嘛。。
3。省略一些不用的转移,比如dp==inf时直接略过,不然会死亡tle。
//Achen
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<cstdio>
#include<vector>
#include<queue>
#include<ctime>
#include<cmath>
#define inf 0x7fffffff
typedef long long LL;
using namespace std;
const int N=13;
int n,m,dis[N][N];
LL dp[N][1<<N];
template<typename T> void read(T &x) {
char ch=getchar(); x=0; T f=1;
while(ch!='-'&&(ch<'0'||ch>'9')) ch=getchar();
if(ch=='-') f=-1,ch=getchar();
for(;ch>='0'&&ch<='9';ch=getchar()) x=x*10+ch-'0'; x*=f;
}
int q1[N],q2[N],t1,t2;
LL cal(int s,int t) {
t1=t2=0;
LL res=0;
for(int i=1;i<=n;i++) {
if(s&(1<<(i-1))) q1[++t1]=i;
if(t&(1<<(i-1))) q2[++t2]=i;
}
for(int i=1;i<=t2;i++) {
int tp=1e9;
for(int j=1;j<=t1;j++)
tp=min(tp,dis[q2[i]][q1[j]]);
res+=tp;
}
return res;
}
void work() {
int nn=(1<<n)-1;
LL ans=1e9;
for(int i=0;i<=n;i++)
for(int j=0;j<=nn;j++)
dp[i][j]=inf;
for(int i=1;i<=n;i++) dp[1][1<<(i-1)]=0;
for(int i=1;i<n;i++) {
for(int s=1;s<=nn;s++) if(dp[i][s]!=inf){
int bj=nn^s;
for(int vv=bj;vv;vv=(vv-1)&bj)
dp[i+1][s|vv]=min(dp[i+1][s|vv],dp[i][s]+i*cal(s,vv));
}
ans=min(ans,dp[i][nn]);
}
ans=min(ans,dp[n][nn]);
printf("%lld\n",ans);
}
void init() {
read(n);
read(m);
memset(dis,127/3,sizeof(dis));
for(int i=1;i<=m;i++) {
int u,v,w;
read(u); read(v); read(w);
dis[u][v]=min(dis[u][v],w);
dis[v][u]=dis[u][v];
}
}
int main() {
#ifdef DEBUG
freopen(".in","r",stdin);
freopen(".out","w",stdout);
#endif
init();
work();
return 0;
}
d2t3列队
--------------------2018-10-13upd------------------------
拿splay打了这题
WA了一面的提交记录,连个splay都打不陈展,真是菜哭自己
1 //Achen 2 #include<bits/stdc++.h> 3 #define For(i,a,b) for(int i=(a);i<=(b);i++) 4 #define Rep(i,a,b) for(int i=(a);i>=(b);i--) 5 #define Formylove return 0 6 const int N=3e6+7; 7 typedef long long LL; 8 typedef double db; 9 using namespace std; 10 int n,m,q; 11 12 template<typename T>void read(T &x) { 13 char ch=getchar(); T f=1; x=0; 14 while(ch!='-'&&(ch<'0'||ch>'9')) ch=getchar(); 15 if(ch=='-') f=-1,ch=getchar(); 16 for(;ch>='0'&&ch<='9';ch=getchar()) x=x*10+ch-'0'; x*=f; 17 } 18 19 int rt[N]; 20 int tot,ch[N][2],p[N]; 21 LL l[N],r[N],sz[N]; 22 #define lc ch[x][0] 23 #define rc ch[x][1] 24 void upd(int x) { sz[x]=sz[lc]+sz[rc]+(r[x]-l[x]+1); } 25 26 void rotate(int x) { 27 int y=p[x],z=p[y],l=(x==ch[y][1]),r=(l^1); 28 if(z) ch[z][y==ch[z][1]]=x; p[x]=z; 29 ch[y][l]=ch[x][r]; p[ch[x][r]]=y; 30 ch[x][r]=y; p[y]=x; 31 upd(y); upd(x); 32 } 33 34 void splay(int &rt,int x) { 35 for(;p[x];rotate(x)) { 36 int y=p[x],z=p[y]; 37 if(z) ((x==ch[y][1])^(y==ch[z][1]))?rotate(x):rotate(y); 38 } 39 rt=x; 40 } 41 42 int find(int &rt,int k) { 43 int x=rt; 44 for(;;) { 45 if(sz[lc]+1<=k&&sz[lc]+r[x]-l[x]+1>=k) { k-=sz[lc]; break; } 46 if(sz[lc]+r[x]-l[x]+1<k) { k-=sz[lc]+r[x]-l[x]+1; x=rc; } 47 else x=lc; 48 } 49 splay(rt,x); 50 if(r[x]!=l[x]) { 51 if(k==1||k==r[x]-l[x]+1) { 52 if(k==1) { l[++tot]=l[x]; r[tot]=l[x]; l[x]++; } 53 else { l[++tot]=r[x]; r[tot]=r[x]; r[x]--; } 54 } 55 else { 56 l[++tot]=l[x]+k; r[tot]=r[x]; r[x]=l[x]+k-2; 57 ch[tot][1]=ch[x][1]; if(ch[x][1]) p[ch[x][1]]=tot; 58 ch[x][1]=tot; p[tot]=x; 59 upd(tot); upd(x); 60 l[++tot]=l[x]+k-1; r[tot]=l[tot]; 61 } 62 upd(tot); 63 return tot; 64 } 65 else { 66 if(!lc) { rt=rc; p[rc]=0; } 67 else if(!rc) { rt=lc; p[lc]=0; } 68 else { 69 int a=lc,b=rc; 70 p[lc]=p[rc]=0; 71 rt=a; while(ch[a][1]) a=ch[a][1]; 72 splay(rt,a); 73 ch[a][1]=b; p[b]=a; 74 upd(a); 75 } 76 lc=rc=0; upd(x); 77 return x; 78 } 79 } 80 81 void insert(int &rt,int y) { 82 if(!rt) { rt=y; return; } 83 int x=rt; 84 while(rc) x=rc; 85 splay(rt,x); 86 rc=y; p[y]=x; upd(x); 87 } 88 89 //#define ANS 90 int main() { 91 #ifdef ANS 92 freopen("1.in","r",stdin); 93 freopen("1.out","w",stdout); 94 #endif 95 read(n); read(m); read(q); 96 For(i,1,n) { 97 rt[i]=++tot; 98 l[tot]=((LL)i-1)*m+1; r[tot]=(LL)i*m-1; 99 upd(tot); 100 } 101 For(i,1,n) { 102 int x=++tot; 103 l[tot]=r[tot]=(LL)i*m; 104 upd(tot); 105 insert(rt[n+1],x); 106 } 107 For(cas,1,q) { 108 int x,y; 109 read(x); read(y); 110 if(y==m) { 111 int t=find(rt[n+1],x); 112 printf("%lld\n",l[t]); 113 insert(rt[n+1],t); 114 } 115 else { 116 int t1=find(rt[x],y); 117 int t2=find(rt[n+1],x); 118 printf("%lld\n",l[t1]); 119 insert(rt[x],t2); 120 insert(rt[n+1],t1); 121 } 122 } 123 Formylove; 124 }