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 }
View Code

 

posted @ 2018-02-04 21:05  啊宸  阅读(208)  评论(0编辑  收藏  举报