• 【20171018校内模拟赛】


    评测机效率约为4e8,开启O2优化,开大栈空间,T1 时限1s,T2/3 时限均为 2s,内存限制为128MB。


    T1 小Z切课本(cut)

    Description

    小Z厌恶数学,他决定将数学课本切成一块一块的。他的课本是一个n*m的矩形,小Z决定切K刀,每刀他可以横着切或者竖着切,但是切成的矩形的长和宽都必须是整数。当然,小Z不会做出两次相同的操作。

    不巧的是,小Z的数学老师知道了他这个行为,并且刁钻的老师肯定会找到切出的矩形中面积最小的那一块来D他,所以小Z想知道最优情况下面积最小的那一块面积最大能是多少?

    Input

    输入数据只包含一行三个整数n,m,k,含义如题目所述。

    Output

    输出一个数字,表示答案。如果没有合法的方案,输出-1。

    Sample Input

    6 4 2

    Sample Output

    8

    Hint

    Subtask1 (20 points) 满足 (n,m leq 10)

    Subtask2 (20 points) 满足(n,m leq 5000)

    Subtask3 (20 points) 满足(n,m leq 10^7)

    Subtask4 (40 points) 满足(n,m leq 10^9)

    Solution

    可以简单的证明出,如果切割次数允许只在同一个方向切,肯定是最优的,

    否则,肯定是将长边切满之后再切短边最优,因此只需要使得切的边最小的尽可能大,所以要尽量等分,最后计算一下答案就好了。

    时空复杂度均为(O(1))

    Code

    #include <stdio.h>
    #define R register
    #define ll long long
    #define AK_titoly ditoly
    #define max(a,b) ((a)>(b)?(a):(b))
    #define file(x) freopen(#x".in","r",stdin);freopen(#x".out","w",stdout);
    inline int read(){
    	R int x; R bool f; R char c;
    	for (f=0; (c=getchar())<'0'||c>'9'; f=c=='-');
    	for (x=c-'0'; (c=getchar())>='0'&&c<='9'; x=(x<<3)+(x<<1)+c-'0');
    	return f?-x:x;
    }
    int n,m,k;
    int main(){
    	file(cut);
    	n=read(),m=read(),k=read();
    	if (k-n-m+2>0) return 0*puts("-1");
    	if (n>m) n^=m,m^=n,n^=m;
    	if (k>=m) printf("%d
    ",n/(k-m+2));
    	else printf("%lld
    ",max(1ll*n*(m/(k+1)),1ll*m*(n/(k+1))));
    	return 0;
    }
    
    

    T2 小Z爱数组(array)

    Description

    小Z最喜欢数组了,现在他得到了由n个正整数组成的数组ai,他想构造一个相同大小的正整数数组bi满足两个数组的差异度(Sigma |ai -bi|)最小。特殊的是,bi数组的所有元素必须满足两两互质。

    Input

    第一行一个数n,表示数组大小。

    接下来一行n个正整数ai,表示给定的数组。

    Output

    输出一行n个正整数bi,表示答案。

    输出的数字必须满足(1 leq bi leq 10^9)。如果有多个答案,你可以输出任意一个。

    Sample Input

    5

    1 6 4 2 8

    Sample Output

    1 5 4 1 9

    Hint

    Subtask1 (20points) 满足$ n leq 8 , 1 leq ai leq 5$

    Subtask2 (30points) 满足$ n leq 50 , 1 leq ai leq 15$

    Subtask3 (50points) 满足$ n leq 100 , 1 leq ai leq 30$

    Solution

    容易发现(1 leq bi leq 58),如果(bi>58) 可以证明用1替代是等价或更优的,显然,58以内的所有质数只能在整个序列中作为最多一个数的质因子出现,经计算的,58以内的质数个数为16个,故所有质数的状态只有(2^{16})种情况,考虑状态压缩,预处理出1~58中每个数所拥有的质因子集合,使用状态压缩DP即可通过。状态转移方程为:$$f[i][S|set[j]]=f[i-1][S]+|ai-j|(1 leq j leq 58 vee set[j]cap S = phi )$$

    ​ 其中(set[j])表示j含有的质因数集合,(f[i][S])表示前i个位置,质因数状态为S的最优答案。

    总复杂度为(O(58n*2^{16})/O(n*2^{16}))

    Code

    #include <stdio.h>
    #include <string.h>
    #define R register
    #define MN 105
    #define inf 0x3f3f3f3f
    #define AK_titoly ditoly
    #define file(x) freopen(#x".in","r",stdin);freopen(#x".out","w",stdout);
    inline int read(){
    	R int x; R bool f; R char c;
    	for (f=0; (c=getchar())<'0'||c>'9'; f=c=='-');
    	for (x=c-'0'; (c=getchar())>='0'&&c<='9'; x=(x<<3)+(x<<1)+c-'0');
    	return f?-x:x;
    }
    inline int abs(int x){return x<0?-x:x;}
    int a[MN],f[MN][1<<16],pre[MN][1<<16],set[MN],n,pn,ans=0,b[MN];
    bool ud[MN];
    void init(){
    	for (R int i=2; i<59; ++i)
    		if (!ud[i]){
    			for (R int j=1; j<=58/i; ++j){
    				ud[i*j]=1;
    				set[i*j]|=(1<<pn);
    			}++pn;
    		}
    }
    int main(){
    	file(array);init();n=read();
    	for (R int i=1; i<=n; ++i) a[i]=read();
    	memset(f,0x3f,sizeof(f));
    	for (R int S=0; S<(1<<16); ++S) f[0][S]=0;
    	for (R int i=1; i<=n; ++i)
    		for (R int j=1; j<59; ++j)
    			for (R int S=0; S<(1<<16); ++S)
    				if (!(set[j]&S)&&f[i][S|set[j]]>f[i-1][S]+abs(j-a[i]))
    					f[i][S|set[j]]=f[i-1][S]+abs(j-a[i]),pre[i][S|set[j]]=j;
    	for (R int S=1; S<(1<<16); ++S) if (f[n][ans]>f[n][S]) ans=S;
    	for (R int i=n; i; --i) b[i]=pre[i][ans],ans^=set[pre[i][ans]];
    	for (R int i=1; i<=n; ++i) printf("%d ",b[i]);
    	return 0;
    }
    
    

    T3 小Z爱修路(road)

    Description

    L国包含n个城市和m条双向道路,第i条道路连接ui,vi两个城市,距离为ti,这些道路将所有n个城市连接在一起。明年,L国将会在首都,也就是1号城市举办一年一度的noi,所以L国的国王委托小Z新建一些道路来减少一些城市到达首都的距离。小Z很快修好了道路,但是他却不是很满意。他想知道最多可以少新建多少道路,满足首都到所有城市的最短路长度和现在相同。

    Input

    第一行读入三个数字n,m,k,依次表示城市的数量,原有道路的数量和新建道路的数量。

    接下来m行,每行三个数字ui,vi,ti,表示一条原有的道路

    最后k行,每行两个数字si,wi,表示一条新建的道路连接1和si,距离为wi。

    Output

    输出一个整数,表示最多能少修建多少条新建的道路。

    Sample Input

    3 2 2

    1 2 1

    2 3 1

    2 2

    3 1

    Sample Output

    1

    Hint

    对于20%的数据,满足(n,m,k leq 100);

    另有20%的数据,满足(k leq 4)

    对于100%的数据,满足(n,k leq 50000 , m leq 200000 , 1 leq ti,wi leq 10^9 si geq 2)

    Solution

    考虑一条新建的边一定会被修建的原因,显然是因为2个原因:

    1.从1号点到这条边的另一端的最短路被修改了

    2.最短路一定包含新的修建的边

    考虑如何维护上述两种情况,显然,只需要求一次原先的最短路,然后求一下现今的最短路,维护新最短路的前驱,并且判断多条最短路时,前驱优先选择非1号点的即可,事实上,由于我们在跑最短路时,1号点只会在开始时更新1次,故只需要在最短路更新或相等时,修改前驱即可。

    总复杂度为$O((m+k) log n) / O(n+m+k) $

    Code

    #include <stdio.h>
    #include <string.h>
    #define MN 50005
    #define MM 200005
    #define M (1<<16)
    #define R register
    #define ll long long
    #define inf 0x3f3f3f3f
    #define INF 0x3f3f3f3f3f3f3f3fll
    #define AK_titoly ditoly
    #define file(f) freopen(#f".in","r",stdin);freopen(#f".out","w",stdout);
    inline int read(){
    	R int x; R bool f; R char c;
    	for (f=0; (c=getchar())<'0'||c>'9'; f=c=='-');
    	for (x=c-'0'; (c=getchar())>='0'&&c<='9'; x=(x<<3)+(x<<1)+c-'0');
    	return f?-x:x;
    }
    inline int min(R int a,R int b){return a<b?a:b;}
    struct node{ll v;int pos;}T[M<<1];
    int to[MM+MN<<1],nxt[MM+MN<<1],v[MM+MN<<1],h[MN],pre[MN],n,m,k,en,ans;
    ll dis[MN],dis2[MN];
    inline void ins(int x,int y,int vl){to[++en]=y,nxt[en]=h[x],v[en]=vl,h[x]=en;}
    inline node min(node a,node b){return a.v<b.v?a:b;}
    inline void A(int k,ll v){for (T[k+=M].v=v; k>>=1; T[k]=min(T[k<<1],T[k<<1|1]));}
    inline void dij(int u,ll *dis){
    	memset(pre,0,sizeof(pre));
    	memset(T,0x3f,sizeof(T));for (R int i=1; i<=n; ++i) T[i+M].pos=i;
    	A(u,0);dis[u]=0;for (R int i=1; i<=n; ++i){
    		u=T[1].pos;A(u,INF);for (R int j=h[u]; j; j=nxt[j]){
    			if (dis[to[j]]>=dis[u]+v[j]) pre[to[j]]=u;
    			if (dis[to[j]]>dis[u]+v[j]) A(to[j],dis[to[j]]=dis[u]+v[j]);
    		}
    	}
    }
    int main(){
    	file(road);
    	memset(dis,0x3f,sizeof(dis));
    	memset(dis2,0x3f,sizeof(dis));
    	n=read(),m=read(),k=read();
    	for (R int i=1; i<=m; ++i){
    		R int x=read(),y=read(),v=read();
    		ins(x,y,v);ins(y,x,v);
    	}dij(1,dis);for (R int i=1; i<=k; ++i){
    		R int x=1,y=read(),v=read();
    		ins(x,y,v);ins(y,x,v);
    	}dij(1,dis2);for (R int i=2; i<=n; ++i)
    		if (dis2[i]<dis[i]&&pre[i]==1) ++ans;
    	printf("%d
    ",k-ans);
    	return 0;
    }
    
  • 相关阅读:
    一个简短的yahoo YUI介绍
    备忘录
    海量数据库查询
    asp.net webshell 解决 方案
    IE=EmulateIE7 标签的作用
    WINDOWS 2003 IIS网站防木马权限设置安全配置整理
    C语言各种函数
    虚函数的各种情况
    equals与==关于Object覆盖和重载问题
    类型转换函数转换为构造类型
  • 原文地址:https://www.cnblogs.com/Melacau/p/20171018test.html
Copyright © 2020-2023  润新知