三十六进制
对于 16进制,我们使用字母 A-F 来表示 10 及以上的数字。
如法炮制,一直用到字母 Z,就可以表示 36 进制。
36 进制中,A表示 10,Z 表示 35,AA 表示370。
你能算出 MANY 表示的数字用 10 进制表示是多少吗?
#include<bits/stdc++.h>
using namespace std;
int main(){
char a='a';
for(int i=0,j=10;i<26;i++,j++){
printf("%d,%c\n",j,a+i);
}
cout<<34+(23*36)+(10*36*36)+(22*36*36*36);
return 0;
}
答案:1040254
(((M36+A)36+N)36+Y)36
进制转换标准做法:
#include<bits/stdc++.h>
using namespace std;
int main(){
string s = "MANY";
int ans = 0;
for(int i = 0; i < s.length(); ++i){
ans *= 36;
if(s[i] > '0' && s[i] <= '9') ans += s[i] - '0';
else ans += s[i] - 'A' + 10;
}
cout << ans;
}
瓷砖样式
小明家的一面装饰墙原来是 3×10 的小方格。
现在手头有一批刚好能盖住2个小方格的长方形瓷砖。
瓷砖只有两种颜色:黄色和橙色。
小明想知道,对于这么简陋的原料,可以贴出多少种不同的花样来。
小明有个小小的强迫症:忍受不了任何2*2的小格子是同一种颜色。
(瓷砖不能切割,不能重叠,也不能只铺一部分。另外,只考虑组合图案,请忽略瓷砖的拼缝)
显然,对于 2×3 个小格子来说,口算都可以知道:一共10种贴法,如【p1.png所示】
但对于 3×10 的格子呢?肯定是个不小的数目,请你利用计算机的威力算出该数字。
注意:你需要提交的是一个整数,不要填写任何多余的内容(比如:说明性文字)
#include<bits/stdc++.h>
using namespace std;
set<string>res;
int g[5][15];
bool check(){
for(int i=1;i<=2;i++){
for(int j=1;j<=9;j++){
if((g[i][j]+g[i+1][j]+g[i][j+1]+g[i+1][j+1])%4==0)return false;
}
}
return true;
}
void dfs(int x,int y){
if(x>3){
if(check()){
string s="";
for(int i=1;i<=3;i++){
for(int j=1;j<=10;j++){
s+=g[i][j]-'0';
}
}
res.insert(s);
}
return ;
}
if(g[x][y]==-1){
if(y+1<=10&&g[x][y+1]==-1){
for(int i=0;i<2;i++){
g[x][y]=g[x][y+1]=i;
if(y+2<=10)dfs(x,y+2);
else dfs(x+1,1);
g[x][y]=g[x][y+1]=-1;
}
}
if(x+1<=3&&g[x+1][y]==-1){
for(int i=0;i<2;i++){
g[x][y]=g[x+1][y]=i;
if(y+1<=10)dfs(x,y+1);
else dfs(x+1,1);
g[x][y]=g[x+1][y]=-1;
}
}
}
else if(y==10)dfs(x+1,1);
else dfs(x,y+1);
}
int main(){
memset(g,-1,sizeof(g));
dfs(1,1);
cout<<res.size();
return 0;
}
答案:101466
发现环
小明的实验室有N台电脑,编号1~N。原本这N台电脑之间有N-1条数据链接相连,恰好构成一个树形网络。在树形网络上,任意两台电脑之间有唯一的路径相连。
不过在最近一次维护网络时,管理员误操作使得某两台电脑之间增加了一条数据链接,于是网络中出现了环路。环路上的电脑由于两两之间不再是只有一条路径,使得这些电脑上的数据传输出现了BUG。
为了恢复正常传输。小明需要找到所有在环路上的电脑,你能帮助他吗?
输入:
第一行包含一个整数N。
以下N行每行两个整数a和b,表示a和b之间有一条数据链接相连。
对于30%的数据,1 <= N <= 1000
对于100%的数据, 1 <= N <= 100000, 1 <= a, b <= N
输入保证合法。
输出:
按从小到大的顺序输出在环路上的电脑的编号,中间由一个空格分隔。
样例输入:
5
1 2
3 1
2 4
2 5
5 3
样例输出:
1 2 3 5
#include<bits/stdc++.h>
using namespace std;
const int N=1e5+5;
vector<int>vec[N];
int d[N];
int main(){
int n;
cin>>n;
for(int i=0;i<n;i++){
int s,v;
cin>>s>>v;
vec[s].push_back(v);
vec[v].push_back(s);
d[s]++;
d[v]++;
}
queue<int>q;
for(int i=1;i<=n;i++){
if(d[i]==1)q.push(i);
}
while(!q.empty()){
int now=q.front();
q.pop();
for(int i=0;i<vec[now].size();i++){
int u=vec[now][i];
d[u]--;
if(d[u]==1)q.push(u);
}
}
for(int i=1;i<=n;i++){
if(d[i]>1)cout<<i<<' ';
}
return 0;
}
希尔伯特曲线
希尔伯特曲线是以下一系列分形曲线 Hn 的极限。我们可以把 Hn 看作一条覆盖 2^n × 2^n 方格矩阵的曲线,曲线上一共有 2^n × 2^n 个顶点(包括左下角起点和右下角终点),恰好覆盖每个方格一次。
[p1.png]
Hn(n > 1)可以通过如下方法构造:
1. 将 Hn-1 顺时针旋转90度放在左下角
2. 将 Hn-1 逆时针旋转90度放在右下角
3. 将2个 Hn-1 分别放在左上角和右上角
4. 用3条单位线段把4部分连接起来
对于 Hn 上每一个顶点 p ,我们定义 p 的坐标是它覆盖的小方格在矩阵中的坐标(左下角是(1, 1),右上角是(2^n, 2^n),从左到右是X轴正方向,从下到上是Y轴正方向),
定义 p 的序号是它在曲线上从起点开始数第几个顶点(从1开始计数)。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
ll f(int n,int x,int y){
if(n==0)return 1;
int m=1<<(n-1);
if(x<=m&&y<=m){//左下角
return f(n-1,y,x);
}
if(x<=m&&y>m){//左上角
return 1ll*m*m+f(n-1,x,y-m);
}
if(x>m&&y>m){//右上角
return 2ll*m*m+f(n-1,x-m,y-m);
}
if(x>m&&y<=m){//右下角
return 3ll*m*m+f(n-1,m-y+1,2*m-x+1);
}
}
int main(){
int n,x,y;
cin>>n>>x>>y;
cout<<f(n,x,y);
return 0;
}
题目日记:左上角,右上角两个递归好写,主要是左下角和右下角的递归困扰我好长时间,题意理解偏差了,终于看懂了;从现在状态转换到上一层状态的哪一个点,刚开始理解的是根据题意顺时针旋转90°放左下角,所以从当前状态转变为上一个状态,我想的是逆时针旋转90°找到对应的点,怎么实结果都不对,忽略了从起点走到终点每个点的顺序是不同的,应该根据走的过程中点的顺序确定改点的上一个状态是哪一个点。
解题过程:
1.根据x,y的值确定是哪个区域
2.左下,右下区域:根据线路行走过程确定上一层那个点与之对应,并用当前值表示上一层对应点的值
3.左上,右上:x,y直接放上去,不需要考虑这一层和上一层x,y点的映射,只需要加上前面区域点的个数,右下也需要加。