教训:考场上宁打暴力,不打高精。
(不过还好A了一道题保底嘿嘿嘿)
T1 题意简述:jzoj5771
Description
此时恰逢春运期间,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
接下来M行,每行三个整数,u、v、w,表示连接u、v的道路需收费w。
接下来N行,第i+M+1行有一个整数Ti,后面Ti个整数,分别是Ci1..CiTi(所有城市编号保证按正整数顺序给出1.. Ti)。
下一行N个整数X1..Xi。
最后一行,两个整数,s、t。
Output
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
“你为什么没背书?”
“没有为什么,我就是没背书。”
“……我去年买了个表,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的含义见题目描述。
Output
代表字典序第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
对于一个正整数N,存在一个正整数T(0<T<N),使得
的值是正整数。
小X给出N,让小Y给出所有可能的T。如果小Y不回答这个神奇的大佬的简单数学题,他学神的形象就会支离破碎。所以小Y求你帮他回答小X的问题。
Input
Output
是整数。
后面是M个数,每一个数代表可能的正整数T(按从小到大的顺序排列)。
Data Constraint
对于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; }