NOIP模拟题 2016.9.3 [数论] [逆序对] [树状数组] [树形dp]
2016-09-03 18:10
489 查看
强迫症
问题描述
人行道铺着两行地砖,第一行每块的长度是A/B,第二行每块的长度是X/Y。两行砖块
第一块的一边是对齐的。
作为一个强迫症患者,看到这样的地砖你很不爽,于是就想知道,最少隔多少距离后两
行地砖的缝隙又会对齐。
输入格式
输入第一行包含一个整数T,表示测试点组数。
接下来T 行,每行两个分数,格式为A/B X/Y,两个分数中间用一个空格隔开。
输出格式
T 行,每行包含一个分数(若答案为整数则输出整数),表示每组数据的答案。分数必
须以最简形式输出。
样例输入
2
3/2 5/8
4/3 3/10
样例输出
15/2
12
数据范围
30%的数据A,B,X,Y<=20
70%的数据T<=10
100%的数据1<=A,B,X,Y,<=10,000,T<=100,000
这个求分数的lcm就好了。
ans = [A/B,X/Y] = [AY,BX]/BY.
手套
问题描述
你现在有N对手套,但是你不小心把它们弄乱了,需要把它们整理一下。N对手套被一字排开,每只手套都有一个颜色,被记为0~N-1,你打算通过交换把每对手套都排在一起。由于手套比较多,你每次只能交换相邻两个手套。请你计算最少要交换几次才能把手套排整齐。
输入格式
输入第一行一个N,表示手套对数。
第二行有2N个整数,描述了手套的颜色。每个数都在0~N-1之间,且每个数字都会出现恰好两次。
输出格式
一行,包含一个数,表示最少交换次数。
样例输入
2
0 1 0 1
样例输出
1
数据范围
30%的数据N≤9;
60%的数据N≤1000;
100%的数据N≤200,000。
这个要把手套放到一起,那么先给手套按出现顺序标号,然后求达到目标状态 {1,1,2,2,3,3,…,n-1,n-1,n,n}所产生的逆序对即可。
这么做是为了尽可能的减少交换次数,保证答案最优。
星座
问题描述
星空中有n颗星星,有n-1对星星间被人为地连上了线,每条连线有各自的长度。所有星星被连成了一个整体。现在,你要在星系中找到一个最大的十字形星座。即,你要找到两条星星构成的路径,使得它们恰好有一颗公共星(这颗公共星不能是某条路径的端点),且两条路径的长度和最大。
左图红线表示了一个合法的十字形星座,而右图的星座并不合法。
输入格式
第一行一个数n,表示星星的数量。
接下来n行,每行3个数x,y,z,表示第x颗星星和第y颗星星间有一条连线,它的长度是z。
输出格式
一行,包含一个整数,表示最大的路径长度和。若答案不存在,输出-1。
样例输入
10
3 8 6
9 3 5
1 9 2
4 8 6
2 3 3
10 4 8
5 9 5
7 2 3
6 9 1
样例输出
33
数据范围
20%的数据n<=1000
50%的数据n<=10,000
100%的数据n<=100,000,0<=z<=1000
这题跟上次那个沿着父亲走的那道树规有点儿像。。
对于每一个可能成为的交叉点的点,第一种情况是这个点下面四条最大的路径之和,第二种情况是这个点下面三条路径与父亲连通的路径之和,那么就可以dp了。
维护dp[u][0,1,2,3]为u以下四条最大路径,f[u]为父亲所连最长路径,转移的话dp数组每个儿子找一下即可,f数组的话,可能是由f[fa[u]]得到,也可能是dp[fa[u]][0],这里注意如果最大路径是由当前v得到,就用dp[fa[u]][1]。
问题描述
人行道铺着两行地砖,第一行每块的长度是A/B,第二行每块的长度是X/Y。两行砖块
第一块的一边是对齐的。
作为一个强迫症患者,看到这样的地砖你很不爽,于是就想知道,最少隔多少距离后两
行地砖的缝隙又会对齐。
输入格式
输入第一行包含一个整数T,表示测试点组数。
接下来T 行,每行两个分数,格式为A/B X/Y,两个分数中间用一个空格隔开。
输出格式
T 行,每行包含一个分数(若答案为整数则输出整数),表示每组数据的答案。分数必
须以最简形式输出。
样例输入
2
3/2 5/8
4/3 3/10
样例输出
15/2
12
数据范围
30%的数据A,B,X,Y<=20
70%的数据T<=10
100%的数据1<=A,B,X,Y,<=10,000,T<=100,000
这个求分数的lcm就好了。
ans = [A/B,X/Y] = [AY,BX]/BY.
#include<iostream> #include<cstdio> #include<cstring> #include<cstdlib> #include<cmath> #include<vector> #include<queue> #include<stack> #include<map> #include<set> #include<string> #include<iomanip> #include<ctime> #include<climits> #include<cctype> #include<algorithm> #ifdef WIN32 #define AUTO "%I64d" #else #define AUTO "%lld" #endif using namespace std; #define smax(x,tmp) x=max((x),(tmp)) #define smin(x,tmp) x=min((x),(tmp)) #define maxx(x1,x2,x3) max(max(x1,x2),x3) #define minn(x1,x2,x3) min(min(x1,x2),x3) typedef long long LL; LL gcd(LL a,LL b) { if(!b) return a; return gcd(b,a%b); } LL lcm(LL a,LL b) {return a/gcd(a,b)*b;} void reduce(LL &a,LL &b) { LL GCD = gcd(a,b); a/=GCD; b/=GCD; } void print(LL a,LL b) { if(b==1) printf(AUTO,a); else printf(AUTO"/"AUTO,a,b); putchar('\n'); } LL A,B,X,Y; int main() { freopen("tile.in","r",stdin); freopen("tile.out","w",stdout); int T; scanf("%d",&T); while(T--) { scanf(AUTO"/"AUTO AUTO"/"AUTO,&A,&B,&X,&Y); LL numer = lcm(A*Y,B*X); LL deno = B*Y; reduce(numer,deno); print(numer,deno); } return 0; }
手套
问题描述
你现在有N对手套,但是你不小心把它们弄乱了,需要把它们整理一下。N对手套被一字排开,每只手套都有一个颜色,被记为0~N-1,你打算通过交换把每对手套都排在一起。由于手套比较多,你每次只能交换相邻两个手套。请你计算最少要交换几次才能把手套排整齐。
输入格式
输入第一行一个N,表示手套对数。
第二行有2N个整数,描述了手套的颜色。每个数都在0~N-1之间,且每个数字都会出现恰好两次。
输出格式
一行,包含一个数,表示最少交换次数。
样例输入
2
0 1 0 1
样例输出
1
数据范围
30%的数据N≤9;
60%的数据N≤1000;
100%的数据N≤200,000。
这个要把手套放到一起,那么先给手套按出现顺序标号,然后求达到目标状态 {1,1,2,2,3,3,…,n-1,n-1,n,n}所产生的逆序对即可。
这么做是为了尽可能的减少交换次数,保证答案最优。
#include<iostream> #include<cstdio> #include<cstring> #include<cstdlib> #include<cmath> #include<vector> #include<queue> #include<stack> #include<map> #include<set> #include<string> #include<iomanip> #include<ctime> #include<climits> #include<cctype> #include<algorithm> #ifdef WIN32 #define AUTO "%I64d" #else #define AUTO "%lld" #endif using namespace std; #define smax(x,tmp) x=max((x),(tmp)) #define smin(x,tmp) x=min((x),(tmp)) #define maxx(x1,x2,x3) max(max(x1,x2),x3) #define minn(x1,x2,x3) min(min(x1,x2),x3) typedef long long LL; #define lowbit(x) ((x)&(-x)) const int maxn = 400005; int sum[maxn<<2]; int n; inline void add(int x,int val) { for(int i=x;i<=n;i+=lowbit(i)) sum[i]+=val; } inline int query(int x) { int ret=0; for(int i=x;i;i-=lowbit(i)) ret += sum[i]; return ret; } int color[maxn]; int a[maxn]; int match[maxn],cur; void init() { scanf("%d",&n); n<<=1; for(int i=1;i<=n;i++) scanf("%d",color+i); for(int i=1;i<=n && cur<=(n>>1);i++) { if(match[color[i]]) continue; match[color[i]]=++cur; } for(int i=1;i<=n;i++) a 152fc [i]=match[color[i]]; } LL calc() { LL ret=0; for(int i=1;i<=n;i++) { ret += i-query(a[i])-1; add(a[i],1); } return ret; } int main() { freopen("gloves.in","r",stdin); freopen("gloves.out","w",stdout); init(); printf(AUTO,calc()); return 0; }
星座
问题描述
星空中有n颗星星,有n-1对星星间被人为地连上了线,每条连线有各自的长度。所有星星被连成了一个整体。现在,你要在星系中找到一个最大的十字形星座。即,你要找到两条星星构成的路径,使得它们恰好有一颗公共星(这颗公共星不能是某条路径的端点),且两条路径的长度和最大。
左图红线表示了一个合法的十字形星座,而右图的星座并不合法。
输入格式
第一行一个数n,表示星星的数量。
接下来n行,每行3个数x,y,z,表示第x颗星星和第y颗星星间有一条连线,它的长度是z。
输出格式
一行,包含一个整数,表示最大的路径长度和。若答案不存在,输出-1。
样例输入
10
3 8 6
9 3 5
1 9 2
4 8 6
2 3 3
10 4 8
5 9 5
7 2 3
6 9 1
样例输出
33
数据范围
20%的数据n<=1000
50%的数据n<=10,000
100%的数据n<=100,000,0<=z<=1000
这题跟上次那个沿着父亲走的那道树规有点儿像。。
对于每一个可能成为的交叉点的点,第一种情况是这个点下面四条最大的路径之和,第二种情况是这个点下面三条路径与父亲连通的路径之和,那么就可以dp了。
维护dp[u][0,1,2,3]为u以下四条最大路径,f[u]为父亲所连最长路径,转移的话dp数组每个儿子找一下即可,f数组的话,可能是由f[fa[u]]得到,也可能是dp[fa[u]][0],这里注意如果最大路径是由当前v得到,就用dp[fa[u]][1]。
#include<iostream> #include<cstdio> #include<cstring> #include<cstdlib> #include<cmath> #include<vector> #include<queue> #include<stack> #include<map> #include<set> #include<string> #include<iomanip> #include<ctime> #include<climits> #include<cctype> #include<algorithm> #ifdef WIN32 #define AUTO "%I64d" #else #define AUTO "%lld" #endif using namespace std; #define smax(x,tmp) x=max((x),(tmp)) #define smin(x,tmp) x=min((x),(tmp)) #define maxx(x1,x2,x3) max(max(x1,x2),x3) #define minn(x1,x2,x3) min(min(x1,x2),x3) const int INF=0x3f3f3f3f; const int maxn = 100005; struct Edge { int to,next; int val; }edge[maxn<<1]; int head[maxn]; int maxedge; int deg[maxn]; inline void addedge(int u,int v,int c) { edge[++maxedge] = (Edge) { v,head[u],c }; head[u] = maxedge; edge[++maxedge] = (Edge) { u,head[v],c }; head[v] = maxedge; deg[u]++; deg[v]++; } int n,root; void init() { scanf("%d",&n); root=(n+1)>>1; memset(head,-1,sizeof(head)); maxedge=-1; for(int i=1;i<n;i++) { int u,v,c; scanf("%d%d%d",&u,&v,&c); addedge(u,v,c); } } int dp[maxn][4],from[maxn][4],f[maxn]; struct Node { int val,id; Node(const int _val,const int _id) { val=_val; id=_id; } bool operator < (const Node t) const { return val >= t.val; } }; void dfs1(int u,int father) { int child=0; for(int i=head[u];~i;i=edge[i].next) if(edge[i].to^father) { child++; break; } if(!child) { dp[u][0]=0; return; } priority_queue <Node> que; int cnt=0; for(int i=head[u];~i;i=edge[i].next) { int v=edge[i].to; if(v==father) continue; dfs1(v,u); if(~dp[v][0]) if(cnt<4 || que.top().val<dp[v][0]+edge[i].val) que.push(Node(dp[v][0]+edge[i].val,v)),cnt++; } while(cnt>4) que.pop(),cnt--; while(cnt) { cnt--; Node t=que.top(); que.pop(); dp[u][cnt]=t.val; from[u][cnt]=t.id; } } void dfs2(int u,int father) { int child=0; for(int i=head[u];~i;i=edge[i].next) if(edge[i].to^father) { child++; break; } if(!child) return; for(int i=head[u];~i;i=edge[i].next) { int v=edge[i].to; if(v==father) continue; int son=-1; for(int k=0;k<4;k++) if(from[u][k]^v) { son=dp[u][k]; break; } if(!~son) son=0; f[v]=max(f[u],son)+edge[i].val; dfs2(v,u); } } inline bool bad_case() { for(int i=1;i<=n;i++) if(deg[i]>=4) return false; return true; } int work() { if(bad_case()) return -1; memset(dp,-1,sizeof(dp)); dfs1(root,-1); dfs2(root,-1); int ret=0; for(int i=1;i<=n;i++) { int t1=0,t2=0; if(~dp[i][3]) t1=dp[i][0]+dp[i][1]+dp[i][2]+dp[i][3]; if(~dp[i][2] && f[i]) t2=f[i]+dp[i][0]+dp[i][1]+dp[i][2]; smax(ret,max(t1,t2)); } return ret; } int main() { freopen("cross.in","r",stdin); freopen("cross.out","w",stdout); init(); printf("%d",work()); return 0; }
相关文章推荐
- NOIP模拟题 2016.10.18 [二分答案] [从上到下的树形DP] [链表翻转]
- NOIP模拟题 2016.11.8 (2) [线段树] [动态逆序对] [矩阵快速幂] [数论] [欧拉函数]
- NOIP模拟题[贪心][DP][数论]
- 【NOIP 模拟题】[T2]拯救紫萱学姐(kmp+树形dp)
- 【NOIP模拟赛】飞(fly) 数论+树状数组
- NOIP模拟题 2016.11.17 [数论] [数位DP] [扫描线] [线段树]
- Codevs 3286 火柴排队 2013年NOIP全国联赛提高组 树状数组,逆序对
- [NOIP模拟题][树状数组][线段树]
- [NOIP2013] 火柴排队 离散化 树状数组 逆序对
- 【loli的胡策】NOIP训练8.10(数论+树形dp+贪心)
- dp 树状数组 逆序元组
- 【NOIP 模拟题】[T2]宝藏(树形dp)
- 【NOIP2016练习】T2 forest (树形DP,数论)
- hzwer2015.9.13 NOIP模拟题 explo seq earth[DP][数论][二分][SPFA]
- HDU 5293 Annoying problem 树形dp dfs序 树状数组 lca
- [NOIP2013提高&洛谷P1966]火柴排队 题解(树状数组求逆序对)
- HDU 2689.求逆序(树状数组)
- hdu2227 && hdu3450 【树状数组优化dp】
- POJ 2299 Ultra-QuickSort 【归并排序 || 树状数组求逆序对数】
- 线段树或树状数组求逆序数