标签:最小 一个 ant next 报告 dig ace pac check
\[\text{R6真TM好玩, 考试的时候玩更好玩}\]
\[\text{By:Rainbow⑥ Block}\]
题目 1 :
预估成绩 : 100 实际成绩 : 100 考试用时 : 2:45 ~ 3:21
花费了45min的时间 考虑各题目 , T1先打了表,找到了优美的性质 ,
\(n\sqrt{n}\)求欧拉函数之前写过,很快实现
题目 2 :
预估成绩 : 30 实际成绩 : 36 考试用时 : 4:26 ~ 5 : 20
先打了30分的暴力, 之后考虑是否可以优化.
找到了很多没用的性质, 最后没有优化成功.
题目 3 :
预估成绩 : 100 实际成绩 : 100 考试用时 : 3 : 25 ~ 4 : 20
01 trie树贪心的模板, 之前写过, 很快实现.
T1 :
写了个爆搜打了个表
发现下列性质:
先盲猜一波欧拉函数,
虽然不会证, 从答案上看没什么问题.
n <= 1e15, \sqrt n 可过
sqrt n 求欧拉函数正好写过www.
若 1 把信写给 x,那么 2 必须把信写给 2x,
以此类推,y 必须把信写个 yx,所以我们要求 x,2x,3x,...,nx 恰好取遍 1...n.
这等价于 x 与 n 互质,所以我们只要求不超过 n 且与 n 互质
的自然数个数,这就是求欧拉函数.
T2 :
C(i) = 约数个数
手玩一下样例:
N = 5:
C(i) = 1, 2, 2, 3, 2
显然, 题目要求约数个数最大的数
由于 C(i) > max{ C(j) }, 1 <= j < i, 要严格大于
若存在两个约数个数最大的数, 选择较小的.
然后可以写出一个O(N sqrt(N))的暴力
若一个数 i 满足条件,我们观察它的唯一分解式 p1^a1 * p2^a2 * ...... * pk^ak,
则 p1,p2,...,pk 一定是前 k 个质数,并且 a1>=a2>=...>=ak,有了这些限制,我们就可以进行搜索,
求出小于 n 的因子数个数最多的数(因子数同样多则选择值最小的).
T3 :
01trie 贪心.
和做过的一道题很像.
异或 , \(a[i] \leqslant 2^{30}\) :
为什么数据范围要写成这个样子? 再考虑异或运算...
想到进行二进制拆分
将 \(a[i]\) 拆分后 , 贪心就可以方便地进行
枚举两 \(01\) 串上 每一位上的数 , 尽量使 各位 相异 或后为 \(0\)
即可选择出最合适的 \(b[i]\)
算法实现:
先建立一棵基于各 \(b[i]\) 的二进制数 的字典树
并记录 各节点代表的 元素出现的个数 \(cnt\)
每次查询操作 , 将 \(a[i]\) 作参数进行传递
从字典树根部 , 开始向下, 查找每一层 (即每一二进制位) 的元素 ,
都尽量使 \(a[i],b[i]\) 此二进制位相异或为 \(1\)
若最优元素在此位置个数为 \(0\) ,选择另一元素
并进入下一层 , 继续进行查找 .
根据字典树的性质 ,
每次查询操作 必然可以找到 一个满足局部最优的 , 最适合 \(a[i]\) 的 \(b[i]\)
查询 \(n\) 次后 , 即可找到最优的答案
注意的点:
为方便运算 ,
要保证 字典树 中 ,二进制数按照正向存储
也就是说,
如果使用位运算符进行二进制拆分, 要先拆出高位 , 再拆出低位
详见代码
T1 :
//知识点:数论
/*
By:Luckyblock
*/
#include <cstdio>
#include <cctype>
#include <vector>
#define ll long long
const ll MARX = 1e15 + 10;
//=================================================
ll N, ans;
std :: vector <ll> p, a;
//=================================================
inline ll read()
{
ll w = 0, f = 1; char ch = getchar();
for(; !isdigit(ch); ch = getchar()) if(ch == '-') f = - 1;
for(; isdigit(ch); ch = getchar()) w = (w << 3) + (w << 1) + (ch ^ '0');
return f * w;
}
//=================================================
int main()
{
N = ans = read();
for(ll i = 2, cnt = 0; i * i <= N; i ++, cnt = 0)
if(N % i == 0)
{
ans /= i, ans *= (i - 1) ;
while(N % i == 0) cnt ++, N /= i;
p.push_back(i); a.push_back(cnt);
}
if(N > 1) ans /= N, ans *= (N - 1), p.push_back(N), a.push_back(1);
printf("%lld", ans);
return 0;
}
/*
#include <cstdio>
#include <algorithm>
#include <ctype.h>
#define min std::min
#define max std::max
#define ll long long
const int MARX = 1010;
//=============================================================
int N, ans, tar[MARX];
bool use[MARX];
//=============================================================
inline int read()
{
int f = 1, w = 0; char ch = getchar();
for(; !isdigit(ch); ch = getchar()) if(ch == '-') f = -1;
for(; isdigit(ch); ch = getchar()) w = (w << 3) + (w << 1) + (ch ^ '0');
return f * w;
}
void check()
{
for(int i = 1; i <= N; i ++)
for(int j = i + 1; j <= N; j ++)
{
int now = (i + j) - ((i + j) > N) * N;
int nowtar = tar[i] + tar[j] - ((tar[i] + tar[j]) > N) * N;
if(tar[now] != nowtar) return ;
}
ans ++;
}
void dfs(int now)
{
if(now == N + 1) {check(); return ;}
for(int i = 1; i <= N; i ++)
if(! use[i])
{
tar[now] = i, use[i] = true;
dfs(now + 1);
use[i] = false;
}
}
//=============================================================
int main()
{
for(int i = 1; i <= 100; i ++)
{
N = i, ans = 0;
dfs(1);
printf("%d %d\n", i, ans);
}
}
*/
T2:
//知识点:数论
/*
By:Luckyblock
*/
#include <cstdio>
#include <algorithm>
#include <ctype.h>
#include <vector>
#define min std::min
#define max std::max
#define ll long long
//=============================================================
int N, Ans, Max;
//=============================================================
inline int read()
{
int s = 1, w = 0; char ch = getchar();
for(; !isdigit(ch); ch = getchar()) if(ch == '-') s = -1;
for(; isdigit(ch); ch = getchar()) w = (w << 1) + (w << 3) + (ch ^ '0');
return s * w;
}
int Get_yueshu(int now)
{
int ret = 0;
for(int i = 1; i * i <= now; i ++)
if(now % i == 0) ret += 1 + (i != (now / i));
return ret;
}
//=============================================================
int main()
{
int N = read();
for(int i = 1; i <= N; i ++)
{
int ret = Get_yueshu(i);
if(Max < ret) Ans = i, Max = ret;
}
printf("%d", Ans);
return 0;
}
#include <cstdio>
#include <cstring>
#define E 510
using namespace std;
typedef long long LL;
LL n, ans;
int prime[E], b[E], cnt = 0;
int maxn;
void dfs(int v, int ended, int now, LL vel)
{
if (now > maxn || now == maxn && vel < ans)
{
ans = vel; maxn = now;
}
for (int i = 1; i <= ended; i++)
{
LL z = prime[v];
if (z*vel > n) break;
vel *= z;
dfs(v+1, i, now*(i+1), vel);
}
}
int main()
{
freopen("au0.in", "r", stdin);
freopen("au0.out", "w", stdout);
memset(b, 0, sizeof(b));
for (int i = 2; i <= 500; i++)
{
if (!b[i])
{
prime[++cnt] = i;
for (int j = i*2; j <= 500; j += i) b[j] = 1;
}
}
scanf("%lld", &n);
if (n <= 2) { printf("%lld\n", n); return 0; }
maxn = 0;
for (int i = 1; i <= 30; i++) dfs(1, i, 1, 1);
printf("%lld\n", ans);
return 0;
}
T3:
//知识点:01trie, 贪心
/*
By:Luckyblock
*/
#include <cstdio>
#include <cctype>
#include <algorithm>
#define ll long long
const int mod = 16777216;
const int MARX = 2e6 + 10;
//==================================================
struct node
{
bool cnt;
int son[2]; //存每个节点代表元素出现次数 , 两儿子
} trie[20 * MARX];
ll N, K, B, P, num = 1, D[MARX];
ll Mul, Ans;
//==================================================
inline int read()
{
int w = 0, f = 1; char ch = getchar();
for(; !isdigit(ch); ch = getchar()) if(ch == '-') f = - 1;
for(; isdigit(ch); ch = getchar()) w = (w << 3) + (w << 1) + (ch ^ '0');
return f * w;
}
inline void Insert(int key) //建树
{
int now = 1; //从根节点开始,向下查找
trie[1].cnt = 1;
for(int i = 30; i >= 0; i --) //将二进制数正向加入字典树
{
int next = (key >> i) & 1ll; //当前位数
if(! trie[now].son[next]) trie[now].son[next] = ++ num; //添加新节点
now = trie[now].son[next];
trie[now].cnt = 1; //增加出现次数
}
}
inline int Query(int key) //回答询问
{
int now = 1, ans = 0; //从根部查找
for(int i = 30; i >= 0; i --)
{
int nowbit = (key >> i) & 1; //当前位
if(trie[now].son[nowbit ^ 1]) ans += (1ll << i),now = trie[now].son[nowbit ^ 1];
else now = trie[now].son[nowbit];
}
return ans;
}
//==================================================
int main()
{
N = read(), K = read(), B = read(), P = read();
for(int i = 1; i <= N; i ++)
{
if(i == 1) D[i] = P;
else D[i] = (K * D[i - 1] % mod + B % mod) % mod;
Insert(D[i]);
}
for(int i = 1; i <= N; i ++)
{
if(i == 1) Mul = 1;
else Mul = Mul * 3 % mod;
Ans = (Ans + Mul * Query(D[i]) % mod) % mod;
}
printf("%lld", (Ans + mod) % mod);
return 0;
}
标签:最小 一个 ant next 报告 dig ace pac check
原文地址:https://www.cnblogs.com/luckyblock/p/12257477.html