2018.8.8提高B组模拟考试

教训:考场上宁打暴力,不打高精。

(不过还好A了一道题保底嘿嘿嘿)

 

T1 题意简述:jzoj5771

 

Description
     MWH寒假外出旅游,来到了S国。S国划分为N个省,第i个省有Ti座城市,编号分别为Ci1,Ci2,……CiTi(各省城市编号不会重复)。所有城市间有M条双向的道路连接,从任意一个城市出发,可到达一切城市,每条道路均须收费。
     此时恰逢春运期间,S国交通运输局采取了优惠措施。当一条路的路费在[L..R]区间时,可免去。同时,每个省也有优惠措施,第i个省内的每条道路路费收其Xi%,连接第i个省和第j个省的每条道路路费收其(Xi%+Xj%)/2。
MWH想从城市s走到城市t,请求出一对L,R,确保:

1.MWH能免费到达目的地;

2.L≤R;

3.L、R均为整数;

4.L尽可能地大,R在满足L最大的前提下最小。

注意:因每条道路由各省的交通运输局直接管辖,所以每条道路的路费必须先得到省级优惠,再得到国家级优惠。
Input
第一行两个整数N,M。
接下来M行,每行三个整数,u、v、w,表示连接u、v的道路需收费w。
接下来N行,第i+M+1行有一个整数Ti,后面Ti个整数,分别是Ci1..CiTi(所有城市编号保证按正整数顺序给出1..  Ti)。
下一行N个整数X1..Xi。
最后一行,两个整数,s、t。
Output
一行两个整数,如题,L和R。
Data Constraint
 

   解题思路:这道题标算是二分答案,但是可以用并查集水过。

             三遍并查集:

             第一遍把边权修改为省级优惠后的边权,然后把边按边权从大到小排序;

             第二遍枚举路径,依次合并,判断s与t连通性,连通时退出;

             第三遍从上次退出的地方开始反向枚举路径,依次合并,判断s与t连通性,连通时退出。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<algorithm>
#define ll long long
#define eps 1e-7
using namespace std;
int n,m,s,t,ansl,ansr,tot,cnt,head[100001];
double fre[100001];
int pro[100001],chk[100001],ans[100001];
struct uio{
    int from,to;
    double val;
}road[500001];
int fa1(int x)
{
    if(x==pro[x]) return x;
    return pro[x]=fa1(pro[x]);
}
void getfa1(int x,int y)
{
    int xx=fa1(x);
    int yy=fa1(y);
    if(xx!=yy) pro[yy]=xx;
}
int fa2(int x)
{
    if(x==chk[x]) return x;
    return chk[x]=fa2(chk[x]);
}
void getfa2(int x,int y)
{
    int xx=fa2(x);
    int yy=fa2(y);
    if(xx!=yy) chk[yy]=xx;
}
int fa3(int x)
{
    if(x==ans[x]) return x;
    return ans[x]=fa3(ans[x]);
}
void getfa3(int x,int y)
{
    int xx=fa3(x);
    int yy=fa3(y);
    if(xx!=yy) ans[yy]=xx;
}
bool cmp(uio x,uio y)
{
    return x.val>y.val;
}
int main()
{
    freopen("trip.in","r",stdin);
    freopen("trip.out","w",stdout);
    scanf("%d%d",&n,&m);
    for(int i=1;i<=100000;i++)
        pro[i]=i,chk[i]=i,ans[i]=i;
    for(int i=1;i<=m;i++)
        scanf("%d%d%lf",&road[i].from,&road[i].to,&road[i].val);
    for(int i=1;i<=n;i++)
    {
        int u;
        scanf("%d",&u);
        for(int j=1;j<=u;j++)
        {
            int v;
            scanf("%d",&v);
            getfa1(i+50000,v);
        }
    }
    for(int i=1;i<=n;i++)
        scanf("%lf",&fre[i]);
    scanf("%d%d",&s,&t);
    for(int i=1;i<=m;i++)
        road[i].val*=(fre[pro[road[i].from]-50000]+fre[pro[road[i].to]-50000])/200;
    sort(road+1,road+1+m,cmp);
    for(int i=1;i<=m;i++)
    {
        ansl=(int)floor(road[i].val+eps);
        getfa2(road[i].from,road[i].to);
        if(fa2(s)==fa2(t)) {tot=i;break;}
    }
    for(int i=tot;i;i--)
    {
        ansr=(int)ceil(road[i].val-eps);
        getfa3(road[i].from,road[i].to);
        if(fa3(s)==fa3(t)) break;
    }
    printf("%d %d\n",ansl,ansr);
    return 0;
}

 


 

T2 题意简述:jzoj5772

 

Description
AK:All kill
“你为什么没背书?”
“没有为什么,我就是没背书。”
“……我去年买了个表,G—U—N!”
头铁王InFleaKing把背书的时间都拿去列排列了......
n=3的排列一共有六个(顺序按字典序从小到大):
1 2 3
1 3 2
2 1 3
2 3 1
3 1 2
3 2 1
气不打一处来的InFleaKing把n的排列打乱了。
他想知道字典序第k小的n的排列是什么?
由于InFleaKing被捉去背书了,所以这个问题只能交给被万人顶礼膜拜的dalao您来解决了。
Input
一行,两个数,分别是n,k。
n,k的含义见题目描述。
Output
一行,n个数。
代表字典序第k小的n的排列。
注意两两数之间要用空格隔开。
Data Constraint
【数据约定】
对于10%的数据:1<=n<=3
对于20%的数据,1<=n<=9
对于30%的数据:1<=n<=18,1<=k<=10^6
对于60%的数据:1<=n<=18
对于80%的数据:1<=n<=100,1<=k<=10^100
对于90%的数据:1<=n<=1000,1<=k<=10^1000
对于100%的数据:1<=n<=100000,1<=k<=min(10^20000,n!)
 

   解题思路:高精+递推。

             从前到后考虑每一位,发现第n位的答案即为在剩下的数中排名第k/(n-1)!的数。

             即:1-->n ans[i]=k%(n-i+1)!/(n-i)!

             由于高精乘法是n^2级别的,考虑对这个式子进行优化。

             发现可以优化为:ans[i]=k/(n-i)!%(n-i+1)

             考虑到6100的阶乘已有100000位,因此复杂度仅为O(6100^2)。

             若高精写法不优,也可考虑压位高精。

             由于本蒟蒻在考试时已被高精搞得死去活来,故没有代码。

 


 

T3 题意简述:jzoj5773

 

Description
      话说, 小X是个数学大佬,他喜欢做数学题。有一天,小X想考一考小Y。他问了小Y一道数学题。题目如下:
      对于一个正整数N,存在一个正整数T(0<T<N),使得

的值是正整数。
      小X给出N,让小Y给出所有可能的T。如果小Y不回答这个神奇的大佬的简单数学题,他学神的形象就会支离破碎。所以小Y求你帮他回答小X的问题。
Input
      一个整数N。
Output
      第一个数M,表示对于正整数N,存在M个不同的正整数T,使得

是整数。
后面是M个数,每一个数代表可能的正整数T(按从小到大的顺序排列)。
Data Constraint
      对于5%的数据,N=1.
      对于20%的数据,N<=5.
      对于40%的数据,N<=1000000
      对于另外20%的数据,答案只有1个,且N为质数,保证对于前60%的数据,当N为质数的时候,答案都一定只有一个,对于这20%的数据,满足2<N。
      对于80%的数据,N<=10^9.
      对于100%的数据,N<=10^14.

 

   解题思路:考虑对式子进行化简。

             (N-T/2)/(N-T)=k --> T=(2k-2)/(2k-1)N

             由于(2k-2)与(2k-1)必互质,因此要使T为正整数,(2k-1)必须是N的因数。

             只需枚举N的因数判断即可。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<algorithm>
#define ll long long
using namespace std;
ll n,ans[1000001];
int main()
{
    freopen("math.in","r",stdin);
    freopen("math.out","w",stdout);
    scanf("%lld",&n);
    ll num=sqrt(n);
    for(ll i=1;i<=num;i++)
    {
        if(n%i) continue;
        if(i%2&&i!=1) ans[++ans[0]]=n/i*(i-1);
        if(n/i%2&&n/i!=1) ans[++ans[0]]=i*(n/i-1);
    }
    sort(ans+1,ans+1+ans[0]);
    printf("%lld ",ans[0]);
    for(ll i=1;i<=ans[0];i++)
        printf("%lld ",ans[i]);
    return 0;
}

 

转载于:https://www.cnblogs.com/water-radish/p/9443531.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值