【纪中2020.4.4日】模拟赛题解

目录:

T1:Swapity Swap
T2:Triangles
T3:Clock Tree

同为三道USACO的题……

正题:

T1:Swapity Swap

题目描述

Farmer John 的 N 头奶牛(1≤N≤10^5)站成一排。对于每一个 1≤i≤N,从左往右数第 i 头奶牛的编号为 i。Farmer John 想到了一个新的奶牛晨练方案。他给奶牛们 M 对整数 (L1,R1)…(LM,RM),其中 1≤M≤100。他让她们重复以下包含 M 个步骤的过程 K(1≤K≤10^9)次:
对于从 1 到 M 的每一个步骤i:当前从左往右数在位置 Li…Ri 的奶牛序列反转她们的顺序。
当奶牛们重复这一过程 K 次后,请对每一个 1≤i≤N 输出从左往右数第 i 头奶牛的编号。

输入

输入的第一行包含 N, M 和 K。对于每一个 1≤i≤M,第 i+1 行包含 Li 和 Ri,均为范围在 1…N 内的整数,其中 Li<Ri。

输出

在第 i 行输出指令序列执行了 K 次后奶牛序列中从左往右数第 i 个元素的编号。

样例输入

7 2 2
2 5
3 7

样例输出

1
2
4
3
5
7
6

分析:

我们用 f[i][j] 记录第 j 个元素,经过2^i次翻转后,这个元素的值。
然后写倍增拆分K,最后输出。

CODE:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long ll;
int n,m,k,a[111],b[111],c[100010],f[35][100010];
int main(){
	freopen("swap.in","r",stdin);
	freopen("swap.out","w",stdout);
    cin>>n>>m>>k;
    for(int i=1;i<=m;i++)cin>>a[i]>>b[i];//读入
    for(int i=1;i<=n;i++)c[i]=i;  //赋初值
    for(int i=1;i<=m;i++)reverse(c+a[i],c+b[i]+1);//反转字符串,模拟
    for(int i=1;i<=n;i++)f[0][i]=c[i];  //经过1次翻转第i个元素的值为c[i]
    for(int i=1;i<=30;i++)
        for(int j=1;j<=n;j++)
            f[i][j]=f[i-1][f[i-1][j]];  //倍增
    for(int i=1;i<=n;i++){
        int x=i,m=k;
        for(int j=30;j>=0;j--)
            if(m>=(1ll<<j)){
                m-=(1ll<<j);  //拆分
                x=f[j][x];
            }
        cout<<x;  //输出
    }
    return 0;
}

T2:Triangles

题目描述

Farmer John 想要给他的奶牛们建造一个三角形牧场。有 N(3≤N≤10^5)个栅栏柱子分别位于农场的二维平面上不同的点 (X1,Y1)…(XN,YN)。他可以选择其中三个点组成三角形牧场,只要三角形有一条边与 x 轴平行,且有另一条边与 y 轴平行。
FJ 可以组成的所有可能的牧场的面积之和等于多少?

输入

第一行包含 N。
以下 N 行每行包含两个整数 Xi 和 Yi,均在范围 −104…104 之内,描述一个栅栏柱子的位置。

输出

由于面积之和不一定为整数且可能非常大,输出面积之和的两倍模 10^9+7 的余数。

样例输入

4
0 0
0 1
1 0
1 2

样例输出

3

分析:

这道题有此公式:
ac+ad+bc+bd=(a+b)*(c+d)
根据这个可以:
按照x坐标从小到大,y坐标从小到大的顺序,依次去枚举每个点i
记录每个横纵坐标各自积累的是多少。当又来了一个新点,则把这个点对应的横坐标位置的和,加上4倍与上一个点之间的距离。

CODE:

#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
long long n,m,sum;
struct node{
	long long x,y;  //横、纵坐标
}a[100010];
bool cmp1(node a,node b){
	return(a.x!=b.x)?a.x<b.x:a.y<b.y;  //根据不同的关键词排序
}
bool cmp2(node a,node b){
	return(a.x!=b.x)?a.x>b.x:a.y<b.y;
}
bool cmp3(node a,node b){
	return(a.x!=b.x)?a.x<b.x:a.y>b.y;
}
bool cmp4(node a,node b){
	return(a.x!=b.x)?a.x>b.x:a.y>b.y;
}
void work(){
long long xx[20010]={},yy[20010]={};
long long x1[20010]={},y1[20010]={};
long long x2[20010]={},y2[20010]={};
	for(int i=1;i<=n;i++){
		long long l=a[i].x;
		long long r=a[i].y;
		x2[l]++;  //相同数的数量
		x1[l]=(x1[l]+abs(r-xx[l])*(x2[l]-1))%1000000007; //计算差
		xx[l]=r;//更新
		y2[r]++;
		y1[r]=(y1[r]+abs(l-yy[r])*(y2[r]-1))%1000000007;
		yy[r]=l;
		//同上
		sum=(sum+x1[l]*y1[r])%1000000007;//公式原理
	}
}
int main(){
	freopen("triangles.in","r",stdin);
	freopen("triangles.out","w",stdout);
	cin>>n;
	for(int i=1;i<=n;i++){
		cin>>a[i].x>>a[i].y;
		a[i].x+=10000;  //数组
		a[i].y+=10000;
	}
	sort(a+1,a+1+n,cmp1);  //排序一次做一次
	work();
	sort(a+1,a+1+n,cmp2);
	work();
	sort(a+1,a+1+n,cmp3);
	work();
	sort(a+1,a+1+n,cmp4);
	work();
	cout<<sum;
	return 0;
}

T3:Clock Tree

题目描述

Farmer John 的新牛棚的设计十分奇怪:它由编号为 1…N 的 N 间房间(2≤N≤2500),以及 N−1 条走廊组成。每条走廊连接两间房间,使得每间房间都可以沿着一些走廊到达任意其他房间。
牛棚里的每间房间都装有一个在表盘上印有标准的整数 1…12 的圆形时钟。然而,这些时钟只有一根指针,并且总是直接指向表盘上的某个数字(它从不指向两个数字之间)。
奶牛 Bessie 想要同步牛棚中的所有时钟,使它们都指向整数 12。然而,她头脑稍有些简单,当她在牛棚里行走的时候,每次她进入一间房间,她将房间里的时钟的指针向后拨动一个位置。例如,如果原来时钟指向 5,现在它会指向 6,如果原来时钟指向 12,现在它会指向 1。如果 Bessie 进入同一间房间多次,她每次进入都会拨动这间房间的时钟。
请求出 Bessie 可能的出发房间数量,使得她可以在牛棚中走动并使所有时钟指向 12。注意 Bessie 并不拨动她出发房间的时钟,但任意时刻她再次进入的时候会拨动它。时钟不会自己走动;时钟只会在 Bessie 进入时被拨动。此外,Bessie 一旦进入了一条走廊,她必须到达走廊的另一端(不允许走到一半折回原来的房间)。

输入

输入的第一行包含 N。下一行包含 N 个整数,均在范围 1…12 之内,表示每间房间初始时的时钟设置。以下 N−1 行每行用两个整数 a 和 b 描述了一条走廊,两数均在范围 1…N 之内,为该走廊连接的两间房间的编号。

输出

输出出发房间的数量,使得 Bessie 有可能使所有时钟指向 12。

样例输入

4
11 10 11 11
1 2
2 3
2 4

样例输出

1

分析:

求起点有多少个,那么我们依次枚举每个点作为起点,把它当做树根,从它出发往孩子走,看看能不能做到。
这样枚举每个点做,每次根确定以后,一遍dfs

CODE:

#include<iostream>
#include<cstdio>
#include<vector>
#include<cstring>
using namespace std;
int n,c[2501],t[2501],ans;
vector<int> a[2501];  //存图
void dfs(int u,int f){  //dfs
    for(int i=0;i<a[u].size();i++){
        int v=a[u][i];
        if(v==f) continue;  //递归孩子节点
        dfs(v,u);
        //求出当前点值
        t[u]=(t[u]-t[v]+12)%12;
    }
}

int main() {
	freopen("clocktree.in","r",stdin);
    freopen("clocktree.out","w",stdout);
    scanf("%d", &n);
    for(int i=1;i<=n;i++){
        scanf("%d",&c[i]);
        c[i]%=12;
    }
    for(int i=0;i<n-1;i++){
        int u,v;
        scanf("%d%d",&u,&v);
        a[u].push_back(v);
        a[v].push_back(u);
    }
    for(int i=1;i<=n;i++){
        memcpy(t,c,sizeof(t));
        //拷贝一遍c数组到t数组里,避免出错
        dfs(i,0);
       //最后根上剩了0或1都可以
        if(t[i]==0||t[i]==1) ans++;
    }
    cout<<ans<<endl;
    return 0;
}

猜你喜欢

转载自blog.csdn.net/dgssl_xhy/article/details/105940859