Test 2018-09-20

【jzoj 4743 NOIP2016 提高 A 组模拟 9.2】积木

(Standard IO)
Time Limits: 1000 ms $ \quad $ Memory Limits: 262144 KB $ \quad $ Detailed Limits
 

Description

pic

Input

第一行包含一个整数 $ n $ 。
接下来 $ n $ 行,每行包含三个整数 $ a,b,c $ ,表示该块积木是一个 $ a \times b \times c $ 的长方体。
 

Output

第一行包含一个整数,表示答案。
 

Sample Input

 3 
 8 7 6 
 3 9 4 
 1 10 5

Sample Output

 18

 

Explanation

选择第 $ 1 $ 块积木和第 $ 3 $ 块积木。
 

Data Constraint

对于 $ 10 $ % 的数据, $ n=1 $ 。
对于 $ 40 $ % 的数据, $ n \le 6 $
对于 $ 100 $ % 的数据, $ 1 \le n \le 15, 1 \le a,b,c \le 10^8 $ 。
 

题解

  • 10 分做法
    输出 $ max(a,b,c) $ 。

  • 40 分做法
    ⽣成全排列,然后枚举每个积⽊哪个⾯朝上,时间复杂度 $ O(n!·3n) $ 。

  • 100 分做法
    显然是状态压缩 $ DP $ 。设计状态 $ f[S][i][0/1/2] $ 表示已经⽤了集合 $ S $ 内的积⽊,
    最顶上是编 号为 $ i $ 的积⽊,它的哪个⾯朝上。转移时枚举不在 $ S $ 内的积⽊,以及朝上的⾯判断即可。时间 复杂度 $ O(2^n ·(3n)^2) $ 。

  • 我的做法: 暴搜(过了)w(゚Д゚)w
     

代码

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int n,a[20],b[20],c[20],ans;
#define INF 100000005
bool vis[20];
void dfs(int res,int A,int B){
	ans=max(ans,res);
	for(int i=1;i<=n;++i)
		if(!vis[i]){
			vis[i]=1;
			if((A>=a[i]&&B>=b[i])||(A>=b[i]&&B>=a[i])) dfs(res+c[i],a[i],b[i]);
			if((A>=a[i]&&B>=c[i])||(A>=c[i]&&B>=a[i])) dfs(res+b[i],a[i],c[i]);
			if((A>=b[i]&&B>=c[i])||(A>=c[i]&&B>=b[i])) dfs(res+a[i],b[i],c[i]);
			vis[i]=0;
		}
	return;
}
int main(){
	scanf("%d",&n);
	for(int i=1;i<=n;++i) scanf("%d %d %d",&a[i],&b[i],&c[i]);
	dfs(0,INF,INF);
	printf("%d",ans);
	return 0;
}

【jzoj 4755 NOIP2016 提高 A 组模拟 9.4】快速荷叶叶变换

(Standard IO)
Time Limits: 1000 ms $\quad $ Memory Limits: 1001472 KB
 

Description

pic

Input

一行,包含两个整数 $ N,M $ 。
 

Output

$ 1 $ 个整数,$ FHT(N,M) \quad mod \quad 1000000007 $ 的值。
 

Sample Input

 3 4 

Sample Output

 1

 

Data Constraint

对于 $ 40 $ % 的数据,$ 1 ≤ N,M ≤ 1000 $
对于 $ 60 $ % 的数据,$ 1 ≤ N,M ≤ 10^6 $
对于 $ 100 $ % 的数据,$ 1 ≤ N,M ≤ 10^9 $
 

题解

  • 直接模拟,期望得分 $ 40 $ 分

\[\sum_{i=1}^N \sum_{j=1}^M (N \quad mod \quad i) \times ( M \quad mod \quad j) \]

\[= \sum_{i=1}^N ( N \quad mod \quad i) \times \sum_{j=1}^M (M \quad mod \quad j) \]

  • 这样分别计算,可以拿到 $ 60 $ 分

  • 考虑对 $ \sum_{i=1}^N ( N \quad mod \quad i) $ 继续化简:

\[\sum_{i=1}^N ( N \quad mod \quad i) = \sum_{i=1}^N ( N - \lfloor \frac{N}{i} \rfloor \times i ) \]

\[=N^2 - \sum_{i=1}^N \lfloor \frac{N}{i} \rfloor \times i \]

  • 因为 $ \lfloor \frac{N}{i} \rfloor $ 只有 $ \sqrt{N} $ 种取值,所以可以分段计数,时间复杂度为 $ O( sqrt{N} ) $
     

代码

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define int long long
#define Mod 1000000007
int n,m,ans1,ans2;
int work(int N){
	int res=N*N%Mod,r;
	for(int l=1;l<=N;l=r+1){
		r=N/(N/l);
		res=(res-(l+r)*(r-l+1)/2%Mod*(N/l)%Mod+Mod)%Mod;
	}
	return (res+Mod)%Mod;
}
signed main(){
	scanf("%lld %lld",&n,&m);
	ans1=work(n); ans2=work(m);
	printf("%lld",ans1*ans2%Mod);
	return 0;
}

【jzoj 4757 NOIP2016 提高 A 组模拟 9.4】树上 摩托

(Standard IO)
Time Limits: 2000 ms $ \quad $ Memory Limits: 1001472 KB $ \quad $ Detailed Limits
 

Description

Sherco 是一位经验丰富的魔♂法师。 Sherco 在第零次圣杯战争中取得了胜利,并取得了王之宝藏——王の树。
他想把这棵树砍去任意条边,拆成若干棵新树,并装饰在他的摩托上,让他的摩托更加酷炫。
但 Sherco 认为,这样生成的树不具有美感,于是 Sherco 想让每棵新树的节点数相同。 他想知道有多少种方法分割这棵树。
 

Input

第一行一个正整数 $ N $ ,表示这棵树的结点总数。
接下来 $ N-1 $ 行,每行两个数字 $ X,Y $ 表示编号为 $ X $ 的结点与编号为 $ Y $ 的结点相连。
结点编号的范围为 $ [1,N] $ 。
 

Output

一个整数,表示方案数。注意,不砍去任何一条边也算作一种方案。
 

Sample Input

 6 
 1 2 
 2 3 
 2 4 
 4 5 
 5 6

Sample Output

 3

 

Data Constraint

对于 $ 40 $ %的数据,$ N ≤ 15 $
对于 $ 60 $ %的数据,$ N ≤ 10^5 $
对于 $ 100 $ %的数据,$ N ≤ 10^6 $ 数据规模非常大,请使用高效的读入方式。
 

题解

  • 暴力枚举删哪些边,期望得分40分。

  • 观察到一些性质:

    • 1.树的大小只可能是 $ N $ 的约数
      2.树的大小确定的话,方案最多只有一种
  • 我们可以枚举树的大小,并 $ DFS $ 判定是否可行。
    时间复杂度 $ O(𝑵 sqrt{𝑵})$ ,期望得分 $ 60 $ 分。

  • 继续观察到一些性质:
    将原树看做一个有根树,一个节点可以作一个块的”根”,
    当且仅当该节点的size能被块的大小整除

  • 预处理出每个节点的 $ size $ ,枚举树的大小 $ k $ ,判断 $ size $ 为 $ k $ 的 倍数的节点数量是否为 $ \frac{𝑵}{ 𝒌} $ 。

  • 时间复杂度$ O(Nln_N) $

 

代码

  • 虽然我 T 了,只要把dfs改成bfs就好啦!( ̄y▽, ̄)╭
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
void read(int &x){
	char ch;x=0;
	while(ch=getchar(),ch<'0'||ch>'9');x=ch-48;
	while(ch=getchar(),ch>='0'&&ch<='9')x=10*x+ch-48;
}
int siz[1000005],num[1000005],n,ans;
int to[2000005],nxt[2000005],head[1000005],tot;
inline void add(int u,int v){ to[++tot]=v; nxt[tot]=head[u]; head[u]=tot; }
void dfs(int u,int fa){
	siz[u]=1;
	for(int i=head[u];i;i=nxt[i])
		if(to[i]!=fa){
			dfs(to[i],u);
			siz[u]+=siz[to[i]];
		}
	++num[siz[u]];
} 
int main(){
	read(n);
	for(int i=1;i<n;++i){
		int u,v;
		read(u); read(v);
		add(u,v); add(v,u);
	}
	dfs(1,0);
	for(int k=1;k<=n;++k)
		if(n%k==0){
			int p=n/k;
			for(int j=k;j<=n;j+=k)
				p-=num[j];
			if(p==0) ++ans;
		}
	printf("%d",ans);
	return 0;
}
posted @ 2018-09-20 20:35  potrem  阅读(263)  评论(0编辑  收藏  举报