zoukankan      html  css  js  c++  java
  • 12.2

    12.2

    自闭double

    又是困得要命的一天,10点前的我是躯体在打代码(乱搞了t1,看了t2没脑子想),10点后才清醒,t3一眼不可做,t4一看树形背包,劈啪乱敲,调过样例,悟到复杂度是(O(nm^2)) 本着骗分第一的思想,又去敲了链和菊花图,想着总该能骗70吧,事实只有5分前面wa后面re 回过头看t2 ,一开始存点位置+状态显然爆空间,一想中间点没用,直接记礼物编号就可,然后预处理礼物之间的距离,一顿状压dp ,可惜没调出来自闭啊

    t1 最小得分和

    挂成了50 呜呜呜

    std的正经暴力做法

    O(KlogN)堆,首先将每相邻两个元素差值入堆,每次选取当前堆中最小的数,找到它在原序列中的位置i,然后向左找到第一个没有取的数对(i,p[i]),将堆顶元素变为s[i]-s[p[i]-1],s[i]为前缀和,然后dec(p[i]),做K次得到答案。

    我是类似的思想 不相似的得分

    #include <queue>
    #include <cstdio>
    #include <ctime>
    #include <iostream>
    #include <algorithm>
    
    using namespace std;
    typedef long long ll;
    const int N=1e6+10;
    inline ll read() {
    	ll x=0;char ch=getchar();
    	while(ch<'0'||ch>'9') ch=getchar();
    	while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
    	return x;
    } 
    
    ll n,k,a[N],ans;
    priority_queue<int>q;
    int main() {
    	n=read();k=read();
    	for(int i=1;i<=n;i++) a[i]=read();
    	sort(a+1,a+1+n);
    	for(int i=2;i<=n;i++) 
    		q.push(a[i]-a[i-1]);
    	while(q.size()>k) q.pop();
    	for(int i=2;i<=n;i++)
    		for(int j=i-2;j>=1;j--) {
    			if(q.size()<k) q.push(a[i]-a[j]);
    			else {
    				int x=q.top();
    				if(x<=a[i]-a[j]) break;
    				else q.pop(),q.push(a[i]-a[j]);
    			}
    		}
    	while(q.size()) 
    		ans+=q.top(),q.pop();
    	printf("%lld
    ",ans);
    	return 0;
    } 
    

    正解

    贪心。
    将序列从小到大排序

    二分这K对数里差值最大的数相差多少,判断是否有大于等于K对满足条件(用个指针扫一遍——单调)

    #include <queue>
    #include <cstdio>
    #include <ctime>
    #include <iostream>
    #include <algorithm>
    
    using namespace std;
    typedef long long ll;
    const int N=1e6+10;
    inline ll read() {
    	ll x=0;char ch=getchar();
    	while(ch<'0'||ch>'9') ch=getchar();
    	while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
    	return x;
    } 
    
    ll n,k,a[N],ans;
    bool check(ll x) {
    	ll cnt=0,j=1;
    	for(ll i=2;i<=n;i++) {
    		while(a[i]-a[j]>x) j++;
    		cnt+=i-j;
    		if(cnt>=k) return 1;
    	}
    	return 0;
    }
    ll sum[N];
    int main() {
    	// freopen("mark9.in","r",stdin);
    	n=read();k=read();
    	for(int i=1;i<=n;i++) a[i]=read();
    	sort(a+1,a+1+n);
    	//二分差值
    	ll l=0,r=a[n]-a[1];
    	while(l<=r) {
    		ll mid=(l+r)>>1;
    		if(check(mid)) r=mid-1;
    		else l=mid+1;
    	}
    	//l 是满足k对的最小差值
    	ll j=1;ll cnt=0;
    	sum[1]=a[1];
    	for(ll i=2;i<=n;i++) {
    		while(a[i]-a[j]>l) ++j;
    		cnt+=i-j;
    		ans+=a[i]*(i-j)-sum[i-1]+sum[j-1];
    		sum[i]=sum[i-1]+a[i];
    	}
    	if(cnt>k) ans-=(cnt-k)*l;
    	printf("%lld
    ",ans);
    	return 0;
    } 
    
    

    t2

    我想的和正解几乎一毛一样

    然而初始化出锅了 ,我只初始化了(f[1][0]=0) ,正解的初始化是对每个礼物起点到它的时间都处理

    然后我一开始写的 dij ,后来嫌麻烦改成bfs ,后来一想是不是队列慢来着(加上队列版的写挂)然后换成递归bfs,一个显然错的最短路,令我自闭改了1小时,回归dij怀抱 ————没事就写dij ,总不会错

    #include <queue>
    #include <cstdio>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    
    using namespace std;
    // typedef long long int;
    #define int long long
    const int N=55;
    const int M=(1<<17)+5;
    inline int read() {
    	int x=0,f=1;char ch=getchar();
    	while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    	while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
    	return f*x;
    }
    inline void Max(int &x,int y){if(x<y)x=y;}
    inline void Min(int &x,int y){if(x>y)x=y;}
    int n,m,T,si,sj,ei,ej;
    char mp[N][N];
    #define MP make_pair
    
    int f[20][M];
    pair<int,int> pos[20];
    int mx,num[M];
    inline int get(int s) {
    	int res=0;
    	for(int j=0;j<mx;j++)
    		if(s&(1<<j))
    			res++;
    	return res;
    }
    
    const int inf=1e15;
    int dx[4]={0,0,-1,1};
    int dy[4]={1,-1,0,0};
    int dis[20][20],id[N][N];
    bool vis[N][N];
    struct node{
    	int r,c,d;
    	node(){}
    	node(int xx,int yy,int dd):r(xx),c(yy),d(dd){}
    	bool operator < (const node &w) const {
    		return d>w.d;
    	}
    };
    priority_queue<node>q;
    
    void get_dis(int u) {
    	vis[pos[u].first][pos[u].second]=1;
    	q.push(node(pos[u].first,pos[u].second,0));
    	while(q.size()) {
    		int x=q.top().r,y=q.top().c,dd=q.top().d;
    		q.pop();
    		for(int i=0;i<4;i++) {
    			int x_=x+dx[i],y_=y+dy[i];
    			if(mp[x_][y_]=='#'||x_<1||y_<1||x_>n||y_>m||vis[x_][y_]) continue;
    			vis[x_][y_]=1;
    			q.push(node(x_,y_,dd+1));
    			if(mp[x_][y_]=='G'||mp[x_][y_]=='Q'||mp[x_][y_]=='K') {
    				Min(dis[u][id[x_][y_]],dd+1);
    				Min(dis[id[x_][y_]][u],dd+1);
    			}
    		}
    	}
    }
    int ans;
    signed main() {
    	n=read();m=read();T=read();
    	for(int i=1;i<=19;i++)
    		for(int j=1;j<=19;j++)
    			if(i!=j)
    				dis[i][j]=inf;
    	for(int i=1;i<=n;i++) {
    		scanf("%s",mp[i]+1);
    		for(int j=1;j<=m;j++) {
    			if(mp[i][j]=='K') 
    				si=i,sj=j;
    			if(mp[i][j]=='G') {
    				id[i][j]=++mx;
    				pos[mx]=MP(i,j);
    			}
    			if(mp[i][j]=='Q') 
    				ei=i,ej=j;
    		}
    	}
    	id[si][sj]=mx+1;pos[mx+1]=MP(si,sj);
    	id[ei][ej]=mx+2;pos[mx+2]=MP(ei,ej);
    	for(int i=1;i<=mx+2;i++) {
    		memset(vis,0,sizeof(vis));
    		get_dis(i);
    	}
    	memset(f,0x3f,sizeof(f));
    	for(int s=0;s<(1<<mx);s++)
    		num[s]=get(s);
    	//初始化,就这写挂了爆零了
    	for(int i=1;i<=mx;i++) {
    		f[i][1<<(i-1)]=dis[mx+1][i];
    		if(f[i][(1<<(i-1))]+2*dis[mx+2][i]<=T)
    			Max(ans,1);
    	}
    
    	for(int s=0;s<(1<<mx);s++) 
    		for(int i=1;i<=mx;i++) {
    			if(s&(1<<(i-1))) continue;
    			for(int j=1;j<=mx;j++) {
    				if(f[j][s]>T||i==j) continue;
    				if(s&(1<<(j-1))) {
    					int now=s|(1<<(i-1));
    					Min(f[i][now],f[j][s]+dis[i][j]*(num[s]+1));
    					int dd=f[i][now]+(num[s]+2)*dis[mx+2][i];
    					if(dd<=T) Max(ans,num[now]);
    				}
    			}
    			
    		}
    	// for(int i=1;i<=mx+2;i++)
    	// 	for(int j=1;j<=mx+2;j++)
    	// 		printf("%lld
    ",dis[i][j]);
    	printf("%lld
    ",ans);
    	return 0;
    }
    

    t3

    咕咕

    t4 树形背包进化

    暴力做法TLE

    #include <cstdio>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    
    using namespace std;
    typedef long long ll;
    const int N=5005;
    inline int read() {
    	int x=0,f=1;char ch=getchar();
    	while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    	while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
    	return f*x;
    }
    inline void Max(int &x,int y){if(x<y)x=y;}
    int n,m;
    int f[N][N<<1];
    int to[N<<1],nxt[N<<1],hd[N],tot,fa[N];
    inline void add(int x,int y) {
    	to[++tot]=y;nxt[tot]=hd[x];hd[x]=tot;
    }
    int v[N],w[N],ans;
    
    void dfs(int x) {
    	for(int i=hd[x];i;i=nxt[i]) {
    		int y=to[i];
    		dfs(y);
    		for(int j=m;j>=0;j--) 
    			for(int k=0;k<=j;k++) 
    				Max(f[x][j],f[y][k]+f[x][j-k]);
    	}
        //这里是强制选x为根否则都是0
    	for(int j=m;j>=0;j--)
    		if(j-v[x]>=0) f[x][j]=f[x][j-v[x]]+w[x];
    		else f[x][j]=0;
    }
    int main() {
    	n=read();m=read();
    	for(int i=1;i<=n;i++) {
    		v[i]=read();
    		fa[i]=read();
    		if(i!=1) add(fa[i],i);
    		w[i]=read();
    	}
    	dfs(1);
    	printf("%d
    ",f[1][m]);
    	return 0;
    }
    

    正解

    选课题解里也提到了这种做法

    先求出树的后(dfs)序,也就是先儿子后父亲 ,(rev[i])(dfn)序为(i)的点编号

    然后显然的转移——见注释

    #include <cstdio>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    
    using namespace std;
    #define int long long
    const int N=5005;
    inline int read() {
    	int x=0,f=1;char ch=getchar();
    	while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    	while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
    	return f*x;
    }
    inline void Max(int &x,int y){if(x<y)x=y;}
    int n,m;
    int f[N][N<<1];
    int to[N<<1],nxt[N<<1],hd[N],tot,fa[N];
    inline void add(int x,int y) {
    	to[++tot]=y;nxt[tot]=hd[x];hd[x]=tot;
    }
    int v[N],w[N],ans;
    int siz[N],rev[N],tim;
    void dfs(int x) {
    	siz[x]=1;
    	for(int i=hd[x];i;i=nxt[i]) {
    		dfs(to[i]);
    		siz[x]+=siz[to[i]];
    	}
    	rev[++tim]=x;
    }
    signed main() {
    	n=read();m=read();
    	v[1]=read();read();w[1]=read();
    	for(int i=2;i<=n;i++) {
    		v[i]=read();fa[i]=read();add(fa[i],i);w[i]=read();
    	}
    	dfs(1);
    	for(int i=1;i<=n;i++)
    		for(int j=m;j>=0;j--) {
    			if(j>=v[rev[i]]) Max(f[i][j],f[i-1][j-v[rev[i]]]+w[rev[i]]);
                //能选它
    			if(i>=siz[rev[i]]) Max(f[i][j],f[i-siz[rev[i]]][j]);//不选它就不选它的子树
    			//显然它的子树编号都比它小
    		}
    	for(int i=1;i<=m;i++)	
    		Max(ans,f[n][i]);
    	printf("%lld
    ",ans);
    	return 0;
    }
    
  • 相关阅读:
    认识EXTJS
    Ext面向对象开发实践(turn)
    20多个在线操作系统(webOS)一览
    一个成功的博客必须知道的80个博客工具
    163.com免费邮箱背后的传奇故事
    Android ListView的滚动条始终显示并且滚动条样式自定义
    eclipse不格式化注释
    Android横屏竖屏切换
    喝茶的好处
    Android设置Gridview中的内容不滚动,然后控件中的内容随便添加的效果。
  • 原文地址:https://www.cnblogs.com/ke-xin/p/14075920.html
Copyright © 2011-2022 走看看