zoukankan      html  css  js  c++  java
  • 20180804的Test

    T1 偏差

    【题目描述】

    给出一个序列A,再给出一段序列B,对于1≤i≤m,可能有B[i]=A[L+i-1]+k,我们称k为这个偏差值,有5个询问:

    1. 偏差值k有几种可能
    2. 偏差值|k|的最小值是多少
    3. L有几种取值方案
    4. L的最小值是多少
    5. L的最大值是多少

    【输入格式】

    多组数据
    第一行一个正整数 n,表示序列 A 的长度。
    第二行 n 个用空格隔开的非负整数 A[1] . . . A[n],描述了序列 A。
    第三行一个正整数 m,表示序列 B 的长度。
    第四行 m 个用空格隔开的非负整数 B[1] . . . B[m],描述了序列 B。

    【输出格式】

    对于每组数据,输出 5 个用空格隔开的整数,依次表示 5 个问题的答案。特别地,对于问题 2, 4, 5,如果无解,请输出 0 作为答案。

    【数据范围与约定】

    (1 leq n , m leq 10^5)


    题解

    有了这个k的存在,让我们很头疼。要是没有这个k该多好,来一个KMP就可以轻松A掉了!因此我们需要把这个k给消掉,你只需要动用你聪明的小脑瓜,使用“瞪眼法”,就会有这一个想法:我们可不可以将A和B序列中相邻的两个数相减,那么这样k的影响就被消去了。此时在来一个KMP就可以搞定啦~~显然这是对的。那么我们就开始码代码了

    代码

    #include<cstdio>
    #include<iostream>
    #include<cmath>
    #include<cstring>
    #include<algorithm>
    #include<cstdlib>
    using namespace std;
    const int N=1000005;
    const int INF=2*1e9+7;
    int n,m,a[N],b[N],p[N],x[N],y[N],x1,x2=INF,x3,x4=INF,x5=-INF,n1,tb[N];
    int main()
    {
    	int T;
    	scanf("%d",&T);
    	while (T--){
    		scanf("%d",&n);
    		memset(p,0,sizeof(p)); x1=0; x2=INF; x3=0; x4=INF; x5=-INF; n1=0;
    		for (int i=1; i<=n; i++) scanf("%d",&a[i]); n--;
    		for (int i=1; i<=n; i++) x[i]=a[i+1]-a[i];
    		scanf("%d",&m);
    		for (int i=1; i<=m; i++) scanf("%d",&b[i]); m--;
    		for (int i=1; i<=m; i++) y[i]=b[i+1]-b[i];
    		if (m!=0){
    			p[1]=0; int j=0;
    			for (int i=1; i<m; i++){
    				while (j>0 && y[j+1]!=y[i+1]) j=p[j];
    				if (y[j+1]==y[i+1]) j++;
    				p[i+1]=j;
    			}
    			j=0;
    			for (int i=0; i<n; i++){
    				while (j>0 && y[j+1]!=x[i+1]) j=p[j];
    				if (y[j+1]==x[i+1]) j++;
    				if (j==m){
    					j=p[j];
    					tb[++n1]=a[i-m+2]-b[1];
    					x2=min(x2,abs(a[i-m+2]-b[1]));
    					x3++; x4=min(x4,i-m+2); x5=max(x5,i-m+2);
    				}
    			}
    			sort(tb+1,tb+1+n1);
    			x1=unique(tb+1,tb+1+n1)-tb-1;
    			if (x2==INF) x2=0; if (x4==INF) x4=0; if (x5==-INF) x5=0;
    			printf("%d %d %d %d %d
    ",x1,x2,x3,x4,x5);	
    		}
    		else {
    			m++; n++;
    			for (int i=1; i<=n; i++) x2=min(x2,abs(b[1]-a[i]));
    			x3=n; x4=1; x5=n;
    			sort(a+1,a+1+n);
    			x1=unique(a+1,a+1+n)-a-1;
    			printf("%d %d %d %d %d
    ",x1,x2,x3,x4,x5);	
    		}
    	}
    	return 0;
    }
    

    T2 闪烁魔法

    【题目描述】

    给一颗树,有边权,有k个插有旗帜的点,需要访问所有插有旗帜的点,且要回到出发点(出发点任选),而且每次访问都是最优的方案,插旗帜的方案是等概率的,求可能情况代价的平均值

    【输入格式】

    本题包含多组数据,第一行一个正整数 T,表示数据组数。接下来依次描述每组数据,对于每组数据:
    第一行 2 个正整数 n, k,分别表示点数,以及插有旗帜的地点的数目。
    接下来 n − 1 行,每行 3 个正整数 u,v,w,表示一条边,连接u,v,边权为w

    【输出格式】

    对于每组数据,输出一行一个正整数,表示期望消耗的魔法值在模998244353 意义下的结果。

    【数据范围与约定】

    $ 1leq kleq mleq 10^5 $


    题解

    若是考虑每一种插旗情况,那实在有点多啊--||,肯定会TLE,因此我们要换一个思路,考虑每一条边。这条边被用到,当且仅当左边的子树有旗帜且右边的子树也有旗帜,故这条边对答案的贡献为:(a代表这条边左子树的点的个数)$ w_i*sum{i=1}k(C_aiC_{n-a}^{k-i})( 但是这个方法的时间复杂度仍然不理想,我们考虑正难则反,可容易推得公式:) w_i(C_nk-C_ak-C_{n-a}^k)$
    接下来就可以愉快的码代码啦~~~

    代码

    #include<cstdio>
    #include<iostream>
    #include<cmath>
    #include<cstring>
    #include<algorithm>
    #include<cstdlib>
    #define N 300005
    #define int long long
    using namespace std;
    const int mod=998244353;
    int n,m,ans,sum[N],head[N],jc[N],jc_inv[N],edgenum=0,vet[N],dis[N],next[N];
    void addedge(int u,int v,int t)
    {
    	vet[++edgenum]=v;
    	next[edgenum]=head[u];
    	head[u]=edgenum;
    	dis[edgenum]=t;
    }
    int inv(int x)
    {
    	if (x==1) return 1;
    	return (mod-mod/x)*inv(mod%x)%mod;
    }
    void init(int n)
    {
    	memset(head,-1,sizeof head); edgenum=ans=0;
    	jc[0]=1;
    	for (int i=1; i<=n; i++) jc[i]=jc[i-1]*i%mod;
    	jc_inv[n]=inv(jc[n]);
    	for (int i=n-1; i>=0; i--) jc_inv[i]=jc_inv[i+1]*(i+1)%mod;
    }
    int C(int x,int y)
    {
    	if (x<y) return 0;
    	return jc[x]*jc_inv[y]%mod*jc_inv[x-y]%mod;
    }
    void calc(int k,int x,int y)
    {
    	int tmp=((C(n,m)-C(x,m)-C(y,m))%mod+mod)%mod;
    	ans=(ans+tmp*k)%mod;
    }
    void dfs(int u,int fa)
    {
    	sum[u]=1;
    	for (int e=head[u],v; e!=-1; e=next[e])
    		if ((v=vet[e])!=fa){
    			dfs(v,u); sum[u]+=sum[v];
    			calc(dis[e],sum[v],n-sum[v]);
    		}
    }
    signed main(){
    	int T;
    	scanf("%lld",&T);
    	while (T--){
    		scanf("%lld%lld",&n,&m);
    		init(n);
    		for (int i=1; i<n; i++){
    			int x,y,z;
    			scanf("%lld%lld%lld",&x,&y,&z);
    			addedge(x,y,z); addedge(y,x,z);
    		}
    		dfs(1,0);
    		ans=ans*2%mod*inv(C(n,m))%mod;
    		printf("%lld
    ",ans);
    	}
    	return 0;
    }	
    

    T3 景中人

    【题目描述】

    给n个整点(横纵坐标均为非负整数),要用矩形把其都覆盖住(确定矩形面积),且每个矩形要贴着直线(y=0),求至少需要几个矩形

    【输入格式】

    本题包含多组数据。第一行一个整数 T,表示数据组数。接下来依次描述各组数据,
    对于每组数据:
    第一行 2 个整数 n, S,表示n个点,矩形面积必须为S。
    接下来 n 行,每行 2 个非负整数 x, y,描述每个点的横纵坐标。

    【输出格式】

    对于每组数据,一行一个整数表示所需要使用的最少的矩形数目。

    【数据范围与约定】

    (nleq 100 ,xleq3*10^6 , 1leq y,Sleq2*10^5)


    题解

    先把坐标离散化。
    首先得知道一个结论:最优解中任意两个矩形的横坐标只可能是相离或包含,不可能是相交。证明略。
    显然区间DP是个不错的选择。
    (f_{l,r,h})为覆盖横坐标(l∼r),纵坐标>h的所有矩形需要的最少次数。
    枚举l,r,h,有两种转移:找到一个横坐标i,使得没有任意一个矩形穿过i。枚举i分治即可。放一个横坐标为(l∼r)的矩形,把高度设为上限。
    对于每一个h,这一层的转移是(O(n^3))的,到下一层的转移是(O(n^2log n)) 的,所以总时间复杂度就是(O(n^4))

    代码

    #include<cstdio>
    #include<iostream>
    #include<cmath>
    #include<cstring>
    #include<algorithm>
    #include<cstdlib>
    using namespace std;
    const int INF=2*1e9+7;
    const int N=105;
    struct node {int x,y;}a[N];
    int n,s,f[N][N][N],tx[N],ty[N],n1,n2,id[N];
    int calc(int x)
    {
    	if (x) return s/x;
        return INF;
    }
    int dfs(int l,int r,int h)
    {
        int &s=f[h][l][r];
        if(~s) return s;
        while(l<=r && id[l]<=h) l++;
        while(l<=r && id[r]<=h) r--;
        if (l>r) return s=0;
        s=INF;
        for(int i=l; i<r; i++) s=min(s,dfs(l,i,h)+dfs(i+1,r,h));
        int hh=calc(tx[r]-tx[l]);
        if (hh<=ty[h]) return s;
        int v=upper_bound(ty+1,ty+n2+1,hh)-ty-1;
        s=min(s,dfs(l,r,v)+1);
        return s; 
    }
    int main()
    {
        int T;
        scanf("%d",&T);
        while (T--) {
    	    scanf("%d%d",&n,&s);
    	    for(int i=1; i<=n; i++){
    		    scanf("%d%d",&a[i].x,&a[i].y);
    		    tx[i]=a[i].x; ty[i]=a[i].y;
    		}
    	    sort(tx+1,tx+n+1); sort(ty+1,ty+n+1);
    	    n1=unique(tx+1,tx+n+1)-tx-1; n2=unique(ty+1,ty+n+1)-ty-1;
    	    memset(f,-1,sizeof f);
    	    for(int i=1; i<=n1; i++) id[i]=0;
    	    for(int i=1; i<=n; i++){
    		    a[i].x=lower_bound(tx+1,tx+n1+1,a[i].x)-tx;
    		    a[i].y=lower_bound(ty+1,ty+n2+1,a[i].y)-ty;
    		    id[a[i].x]=max(id[a[i].x],a[i].y);
    		}
    	    int ans=dfs(1,n1,0);
    	    printf("%d
    ",ans);
    	}
        return 0;
    }
    

    总结:

    今天LOJ大吉,洛谷大凶,真是矛盾啊...为我脸黑埋伏笔这里写图片描述
    这里写图片描述
    这估计也是注定了我要么A掉,要么爆零的脸黑结果吧
    这套题,说难不难,说简单不简单,镇中大佬集体RP爆降是我排名虚高的原因。不能因此而嘚瑟

    T1 100/100

    这道题,看题3min就出正解,虽说KMP稍有忘却,但还是可以1h AC,稳!!

    T2 0/100

    这道题,暴力居然WA了,如此脸黑的我也很无奈啊╮(╯▽╰)╭,后面急于写正解,也没有时间去过多关注如何WA的,估计是手抖吧,但是没有想到基于边的算法,这说明思路过于局限,不过之前也从未做过此类题,情有可原。

    T3 0/100

    唔,错误贪心,我也是走投无路啊,曾经想到过DP(一闪而现),但是思路被我一秒枪毙(感觉不对+写不出来)...终究还是只能归结于太嫩了,题目做得太少。

    心得:

    题目还是要多做啊,拓宽视野,算法的不足也要及时补上,加油吧。
    正因为生命有限,所以才显得更重要,正因为生命有限,所以才更应该努力不懈。

  • 相关阅读:
    非凸问题寻优
    非凸问题寻优
    函数的微分表
    函数的微分表
    图形的认识(curve,surface,hypersurface)
    几种Java写webservice的比较
    C#利用lambda在函数中创建内部函数
    uva 387 A Puzzling Problem (回溯)
    HDU 4336 Card Collector 数学期望(容斥原理)
    【ArcGIS 10.2新特性】Portal for ArcGIS新特性
  • 原文地址:https://www.cnblogs.com/wangyh1008/p/9420910.html
Copyright © 2011-2022 走看看