T1.小 Z 切课本(cut)
小 Z 厌恶数学,他决定将数学课本切成一块一块的。他的课本是一个 n*m 的
矩形,小 Z 决定切 K 刀,每刀他可以横着切或者竖着切,但是切成的矩形的长和
宽都必须是整数。当然,小 Z 不会做出两次相同的操作。
不巧的是,小 Z 的数学老师知道了他这个行为,并且***钻的老师肯定会找到
切出的矩形中面积最小的那一块来 D 他, 所以小 Z 想知道最优情况下面积最小
的那一块面积最大能是多少?
[输入格式]
从 cut.in 中读取数据。
输入数据只包含一行三个整数 n,m,k,含义如题目所述。
[输出格式]
输出一个数字,表示答案。 如果没有合法的方案,输出-1。
[样例输入]
6 4 2
[样例输出]
8

[数据范围与约定]

本题采用子任务制,你只有通过一个 subtask 下的所有测试点才能得到对应的分
数。
Subtask1 : 包含 20Points 满足 n,m<=10
Subtask2 : 包含 20Points 满足 n,m<=5000
Subtask3 : 包含 20Points 满足 n,m<=10^7
Subtask4 : 包含 40Points 满足 n,m<=10^9
对于所有数据,满足 n,m,k>=1, k<=10^9

题解

如果能只切一边的话,只切一边一定最优。
假设 n<=m, k>=m 时,考虑将一边全部切开,剩下的平均切到另一边。 长的边切 m-1 刀,
另一边切 k-(m-1)刀一定最优因为, n/(k-(n-1))>=m/(k-(m-1))。

 

#include<cstdio>
long long n,m,k;
int main(){
    freopen("cut.in","r",stdin);
    freopen("cut.out","w",stdout);
    scanf("%lld%lld%lld",&n,&m,&k);
    if(n+m-2<k){
        puts("-1");return 0;
    }
    if(n>m){
        long long t=n;n=m;m=t;
    }
    if(m>=k+1){
        if(n/(k+1)*m>m/(k+1)*n) printf("%lld",n/(k+1)*m);
        else printf("%lld",m/(k+1)*n);
    }
    else{
        if(m/(k-(n-1)+1)>n/(k-(m-1)+1)) printf("%lld",m/(k-(n-1)+1));
        else printf("%lld",n/(k-(m-1)+1));
    }
    return 0;
}

T2.小 Z 爱数组(array)
小 Z 最喜欢数组了,现在他得到了由 n 个正整数组成的数组 ai,他想构造
一个相同大小的正整数数组 bi 满足两个数组的差异度 |ai - bi|最小。特殊的

是, bi 数组的所有元素必须满足两两互质。

题解

原题 ai 不超过 30,所以选择的 bi 肯定小于 59,不然可以用 1 代替。
58 以内只有 16 个质数,所以将这些质数的状态压起来之后 dp 即可,复杂度 O(2^16*n*58)
T3.小 Z 爱修路
把所有新加的边去个重,到相同的点的边只保留一个最小的,然后跑一次最短路。一条新加
的边如果长度不是最短路一定可以去掉,否则只有满足有其它最短路径到达这个点的时候才
可以去掉。算出到每个点最短路条数是否大等于 2 即可。
复杂度 O((n+k)logn)

还没打,先贴标程。

#include<iostream>
#include<cstring>
#include<cstdio>
#define MN 100
using namespace std;
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 x*f;
}
const int p[16]={2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53};
int f[MN+5][1<<16],from[MN+5][1<<16],n,a[MN+5],bit[MN+5],q[MN+5];
void R(int&x,int&y,int X,int Y){X<x?(x=X,y=Y):0;}
inline int abs(int x){return x<0?-x:x;}
int main()
{
    freopen("array.in","r",stdin);
    freopen("array.out","w",stdout);
    n=read();
    for(int i=1;i<=n;++i) a[i]=read();
    memset(f,63,sizeof(f));f[0][0]=0;
    for(int i=1;i<59;++i)
        for(int j=0;j<16;++j) if(i%p[j]==0) bit[i]|=1<<j;
    for(int i=1;i<=n;++i) for(int j=0;j<1<<16;++j) if(f[i-1][j]<1e9)
        for(int k=1;k<59;++k) if(!(bit[k]&j)) R(f[i][j|bit[k]],from[i][j|bit[k]],f[i-1][j]+abs(k-a[i]),k);
    int mn=1e9,fr=0;
    for(int i=0;i<1<<16;++i) if(f[n][i]<mn) mn=f[n][i],fr=i;
    for(int i=n,j=fr;i;j^=bit[from[i--][j]]) q[i]=from[i][j];
    for(int i=1;i<=n;++i) printf("%d ",q[i]);
    return 0;    
}

T3.小 Z 爱修路(road)
L 国包含 n 个城市和 m 条双向道路,第 i 条道路连接 ui,vi 两个城市, 距离为
ti,这些道路将所有 n 个城市连接在一起。 明年, L 国将会在首都,也就是 1 号
城市举办一年一度的 noi,所以 L 国的国王委托小 Z 新建一些道路来减少一些城
市到达首都的距离。小 Z 很快修好了道路,但是他却不是很满意。他想知道最多
可以少新建多少道路,满足首都到所有城市的最短路长度和现在相同。
[输入格式]
从 road.in 中读取数据。
第一行读入三个数字 n,m,k,依次表示城市的数量,原有道路的数量和新建道路
的数量。
接下来 m 行,每行三个数字 ui,vi,ti,表示一条原有的道路
最后 k 行,每行两个数字 si,wi,表示一条新建的道路连接 1 和 si,距离为 wi。
[输出格式]
输出一个整数,表示最多能少修建多少条新建的道路。
[样例输入]
3 2 2
1 2 1
2 3 1
2 2
3 1
[样例输出]
1 

把所有新加的边去个重,到相同的点的边只保留一个最小的,然后跑一次最短路。一条新加
的边如果长度不是最短路一定可以去掉,否则只有满足有其它最短路径到达这个点的时候才
可以去掉。算出到每个点最短路条数是否大等于 2 即可。
复杂度 O((n+k)logn)

#include<cstdio>
#include<cstring>
struct edge{
    int to,w,nx;
}e[5000001];
int q[5000001],he,ta;
int h[50010],p;
int n,m,k;
void ae(int fr,int to,int w){
    e[++p]=(edge){to,w,h[fr]};h[fr]=p;
}
long long d[50010];
int vis[50010],can[50010];
void spfa(){
    for(int i=1;i<=n;i++) d[i]=0x3f3f3f3f3f3f3f3f;
    d[1]=0;
    q[++ta]=1;
    for(int i=1,x,y;i<=k;i++){
        scanf("%d%d",&x,&y);
        if(d[x]>y){
            d[x]=y,can[x]=1;
            if(vis[x]==0){
                vis[x]=1;
                q[++ta]=x;
            }
        }
    }
    while(he<ta){
        int u=q[++he];
        vis[u]=0;
        for(int i=h[u];i;i=e[i].nx){
            int v=e[i].to,dis=e[i].w;
            if(d[v]>=d[u]+dis&&can[v]) can[v]=0;
            if(d[v]>d[u]+dis){
                d[v]=d[u]+dis;
                if(vis[v]==0){
                    vis[v]=1;
                    q[++ta]=v;
                }
            }
        }
    }
    for(int i=1;i<=n;i++)k-=can[i];
    printf("%d\n",k);
}
int main(){
    freopen("road.in","r",stdin);
    freopen("road.out","w",stdout);
    scanf("%d%d%d",&n,&m,&k);
    for(int u,v,w,i=1;i<=m;i++)scanf("%d%d%d",&u,&v,&w),ae(u,v,w),ae(v,u,w);
    spfa();
    return 0;
}

爆int爆得好爽。。。

 

posted on 2017-10-18 22:51  nzher  阅读(330)  评论(0编辑  收藏  举报