您的位置:首页 > 其它

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.

#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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息