比赛地址
A 递推数
题目叙述
求递推数列的a[a[a[a[n]]]]
解法
方法是暴力。。。
一开始用一个暴力的代码(复杂度 O(n))跑 1min 左右跑出来 a[n] 对于 1e9+7 的循环节 222222224LL , 然后继续跑出来 222222224LL 的循环节 183120LL 然后跑出来 183120LL 的循环节 240LL。于是整个问题就简单了, 矩阵快速幂算出第n位mod 240 , 然后再改mod 为 183120LL ,然后再改成 222222224LL ,然后再改成 1e9 + 7..
Code
暴力代码:
(偷懒暴力代码也用矩阵写的。。。)
/*
* =====================================================================================
*
* Author: KissBuaa.DS(AC)
* Company: BUAA-ACMICPC-Group
*
* =====================================================================================
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
//#include <stdbool.h>
#include <math.h>
#define LL long long
#define CLR(x) memset(x,0,sizeof(x))
#define typec LL
#define sqr(x) ((x)*(x))
#define abs(x) ((x)<0?(-(x)):(x))
#define min(a,b) ((a)<(b)?(a):(b))
#define max(a,b) ((a)>(b)?(a):(b))
#define PI acos(-1.0)
#define lowbit(x) ((x)&(-(x)))
#define lson l , m , rt << 1
#define rson m + 1 , r , rt << 1 | 1
#define inf 100000000
//For C++
#include <cctype>
#include <algorithm>
#include <vector>
#include <map>
#include <set>
#include <queue>
#include <stack>
#include <bitset>
#include <list>
#include <iostream>
using namespace std;
const double eps=1e-10;
int dblcmp(typec d) {
if (fabs(d)<eps)
return 0;
return (d>0)?1:-1;
}
LL modo;
const int maxn=3;
class Mat
{
public:
LL Matn,Matm;
typec a[maxn][maxn];
Mat()
{
Matn=0;
Matm=0;
memset(a,0LL,sizeof(a));
}
void output();
void init();
void initI();
Mat mul(const Mat &a);
Mat power(const Mat&a,LL k);
};
void Mat::output()
{
for (int i=0;i<Matn;++i)
{
for (int j=0;j<Matm;++j)
{
if (j!=0) printf(" ");
printf("%I64d",a[i][j]);
}
printf("\n");
}
}
void Mat::init()
{
Matn=0;
Matm=0;
memset(a,0LL,sizeof(a));
}
Mat Mat::mul(const Mat &A)
{
Mat c;
c.init();
c.Matn=Matn;
c.Matm=A.Matm;
for (int i=0;i<Matn;++i)
for (int j=0;j<A.Matm;++j)
{
for (int k=0;k<Matm;++k)
{
c.a[i][j]=(c.a[i][j]+(a[i][k]*A.a[k][j])%modo)%modo;
}
}
return c;
}
void Mat::initI()
{
memset(a,0LL,sizeof(a));
for (int i=0;i<Matn;++i) a[i][i]=1LL;
}
Mat Mat::power(const Mat& a,LL k)
{
Mat c=a,b;
b.init();
b.Matn=a.Matn;b.Matm=a.Matm;
b.initI();
while (k)
{
if (k & (1LL))
b=b.mul(c);
c=c.mul(c);
k>>=1LL;
}
return b;
}
Mat A ,B;
LL g(LL x){
//Mat A;
if (x == 0LL) return 0LL;
if (x == 1LL) return 1LL;
//A.init();
//A.Matn = 1LL , A.Matm = 2LL;
//A.a[0][0]=1LL,A.a[0][1]=0LL;
//Mat B;
B.init();
B.Matn = 2LL , B.Matm = 2LL;
B.a[0][0]= 3LL, B.a[1][0]=1LL;
B.a[0][1] = 1LL; B.a[1][1]=0LL;
B = B.power(B , x - 1LL);
//A = A.mul(B);
return B.a[0][0];
}
LL n;
set< pair<LL , LL> > has;
#define MP make_pair
void solve(){
has.clear();
LL i;
LL pre = g(1);
for (i = 2 ; ; ++i){
LL res = g(i);
if(has.find( MP(pre , res) ) != has.end()){
cout<<i - 2<<endl;
return;
}
has.insert( MP(pre , res) );
pre = res;
}
}
int main(){
modo = 1e9 + 7;
solve();
// freopen("0.in" , "r" , stdin);
// freopen("0.out" , "w" , stdout);
// int T;
// cin >> T;
// while (T--) solve();
// while(~scanf("%I64d" , &n)) solve();
}
于是得到了这个之后就能用
快速幂代码:
/*
* =====================================================================================
*
* Author: KissBuaa.DS(AC)
* Company: BUAA-ACMICPC-Group
*
* =====================================================================================
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
//#include <stdbool.h>
#include <math.h>
#define LL long long
#define CLR(x) memset(x,0,sizeof(x))
#define typec LL
#define sqr(x) ((x)*(x))
#define abs(x) ((x)<0?(-(x)):(x))
#define min(a,b) ((a)<(b)?(a):(b))
#define max(a,b) ((a)>(b)?(a):(b))
#define PI acos(-1.0)
#define lowbit(x) ((x)&(-(x)))
#define lson l , m , rt << 1
#define rson m + 1 , r , rt << 1 | 1
#define inf 100000000
//For C++
#include <cctype>
#include <algorithm>
#include <vector>
#include <map>
#include <set>
#include <queue>
#include <stack>
#include <bitset>
#include <list>
#include <iostream>
using namespace std;
const double eps=1e-10;
int dblcmp(typec d) {
if (fabs(d)<eps)
return 0;
return (d>0)?1:-1;
}
LL modo;
const int maxn=3;
class Mat
{
public:
LL Matn,Matm;
typec a[maxn][maxn];
Mat()
{
Matn=0;
Matm=0;
memset(a,0LL,sizeof(a));
}
void output();
void init();
void initI();
Mat mul(const Mat &a);
Mat power(const Mat&a,LL k);
};
void Mat::output()
{
for (int i=0;i<Matn;++i)
{
for (int j=0;j<Matm;++j)
{
if (j!=0) printf(" ");
printf("%I64d",a[i][j]);
}
printf("\n");
}
}
void Mat::init()
{
Matn=0;
Matm=0;
memset(a,0LL,sizeof(a));
}
Mat Mat::mul(const Mat &A)
{
Mat c;
c.init();
c.Matn=Matn;
c.Matm=A.Matm;
for (int i=0;i<Matn;++i)
for (int j=0;j<A.Matm;++j)
{
for (int k=0;k<Matm;++k)
{
c.a[i][j]=(c.a[i][j]+(a[i][k]*A.a[k][j])%modo)%modo;
}
}
return c;
}
void Mat::initI()
{
memset(a,0LL,sizeof(a));
for (int i=0;i<Matn;++i) a[i][i]=1LL;
}
Mat Mat::power(const Mat& a,LL k)
{
Mat c=a,b;
b.init();
b.Matn=a.Matn;b.Matm=a.Matm;
b.initI();
while (k)
{
if (k & (1LL))
b=b.mul(c);
c=c.mul(c);
k>>=1LL;
}
return b;
}
Mat A ,B;
LL g(LL x){
//Mat A;
if (x == 0LL) return 0LL;
if (x == 1LL) return 1LL;
//A.init();
//A.Matn = 1LL , A.Matm = 2LL;
//A.a[0][0]=1LL,A.a[0][1]=0LL;
//Mat B;
B.init();
B.Matn = 2LL , B.Matm = 2LL;
B.a[0][0]= 3LL, B.a[1][0]=1LL;
B.a[0][1] = 1LL; B.a[1][1]=0LL;
B = B.power(B , x - 1LL);
//A = A.mul(B);
return B.a[0][0];
}
LL n;
void solve(){
scanf("%lld", &n);
LL res;
//printf("%I64d\n",g(42837));
modo = 240LL;
res = g(n);
modo = 183120LL;
res = g(res);
//res = (res * inv(res , modo))% modo;
//cout<<res<<endl;
modo = 222222224LL;
res = g(res);
//cout<<res<<endl;
//res = (res * inv(res , modo))% modo;
modo =(1000000000LL + 7LL);
res = g(res);
//res = (res * inv(res-1LL , modo))% modo;
//printf("%I64d\n",g(g(g(n))));
printf("%lld\n",res);
}/*
set< pair<LL , LL> > has;
#define MP make_pair
void solve(){
has.clear();
LL i;
LL pre = g(1);
for (i = 2 ; ; ++i){
LL res = g(i);
if(has.find( MP(pre , res) ) != has.end()){
cout<<i - 2<<endl;
return;
}
has.insert( MP(pre , res) );
pre = res;
}
}
*/
int main(){
// modo = 12LL;
solve();
// freopen("0.in" , "r" , stdin);
// freopen("0.out" , "w" , stdout);
int T;
cin >> T;
while (T--) solve();
// while(~scanf("%I64d" , &n)) solve();
}
另
这题比较贱的是我故意选择了答案是 0 和 1 的答案,发现好多啊。。。
这是个原题,我觉得太好玩儿了就拿过来了。。。
B 郭式树
题目描述:
求 abs(x - y)
解法:
longlong 的 x - y 会溢出,所以只要特判加起来是 2 ^ 63 的两种情况即可。。。。
Code:
void solve(){
LL a , b;
RD(a , b);
if (a == 4611686018427387904ll && b == -4611686018427387904ll)
printf("9223372036854775808\n");
else if (b == 4611686018427387904ll && a == -4611686018427387904ll)
printf("9223372036854775808\n");
else OT(abs(a - b));
}
int main(){
//#ifdef LOCAL
// freopen("0.in" , "r" , stdin);
// freopen("0.out" ,"w" , stdout);
//#endif
Rush solve();
}
另
这题的高精度方法是被我故意卡掉的。。。
C 面面数
题目
求原问题答案 >= n 的最小的数
解法:
推出公式 + 二分,公式就是 n ^ 2 - n + 2, 然后特殊判断一下 n = 1 输出 0 的情况即可
Code:
LL n;
void solve(){
RD(n);
if (n == 1){
puts("0");
return;
}
LL low = 1 , high = 1e5 , mid , ret = high;
do{
mid = low + high >> 1;
if (mid * mid - mid + 2 >= n){
checkMin(ret , mid);
high = mid - 1ll;
}
else low = mid + 1ll;
}while(low <= high);
OT(ret);
}
int main(){
// freopen("0.in" , "r" , stdin);
// freopen("0.out" , "w" , stdout);
Rush solve();
}
D 平衡树
这题准备和 CF #173 E 一起讲。
题目:
求一个数在一堆数选一个数,最大的异或值
CF : 求数列不重叠前缀 & 后缀 最大异或值
解法:
用Trie 或者手写二叉树,来记录每个数字的每一个二进制位。
试想,对于一个数字x,在ai里面找最大的异或值,其实就是一个贪心的过程:
1、把x每一位取反(0->1 , 1 -> 0)
2、从最高位开始找,如果最高位和x取反的最高位相等,那么异或值的最高位就是 1 , 如果没有的话只能是 0 了。
3、不停滴做 2,于是就是在二叉树 / Trie 上面尽可能找和 1 之后的x尽量“匹配”的数字即可。
复杂度理论是O(n)
Code
struct node{
int son[2] , value;
void reset(){
son[0] = -1 , son[1] = -1 , value = -1;
}
}tree[32 * 10000];
int id;
int mm[32];
int dig[32];
char op[10];
void getdig(int x , int rev){
for (int i = 0 ; i < 32 ; ++i)
dig[i] = ((x & mm[31 - i]) != 0) ^ rev;
}
void insert(int x){
getdig(x , 0);
int root = 0;
for (int i = 0 ; i < 32 ; ++i){
if (tree[root].son[dig[i]] == -1){
tree[root].son[dig[i]] = ++id;
tree[id].reset();
}
root = tree[root].son[dig[i]];
}
tree[root].value = x;
}
int query(int x , int rev){
getdig(x , rev);
int root = 0;
for (int i = 0 ; i < 32 ; ++i){
// OT(dig[i]);
if (tree[root].son[dig[i]] == -1) root = tree[root].son[(dig[i] ^ 1)];
else root = tree[root].son[dig[i]];
}
return x ^ tree[root].value;
}
void solve(){
id = 0;
tree[0].reset();
Rush{
RS(op);
if (op[0] == 'i') insert(RD());
else OT(query(RD() , op[2] == 'a'));
}
}
void init(){
REP(i , 32) mm[i] = 1 << i;
}
int main(){
init();
Rush solve();
}
另
这题暴力是绝对不可能通过的,我跑了 5.5 h。。。。
CF #173 E
这题的数据结构和上面的一样只不过建立不太相同
1、首先 1 ~ n 枚举 前 i 个数的异或值
2、将树情况,插入 0
3、从 n -> 1 枚举,每次i前缀异或值 在树中查找 max , 记录 ; 然后将后缀异或值 插入树,并且将后缀异或值 和 max 进行比较。
那么一趟下来之后,也就是枚举了每个前缀(包括空)对于不重叠后缀们的异或最大值。
代码请看
http://codeforces.com/contest/282/submission/3311133
E 同心树
这题也给CF #172 Div 1 A 了。。。竟然被吐槽了。。。题目:
求两个正方形旋转的面积交\CF 矩形OOXX
解法:
1、裸半平面交 【【【【这个没必要说吧 - - 。 其实我出这个题目的本意是用半平面交来测试数据,E 这个题目半平面交是肯定超时的。2、计算四个三角形的面积剪掉。
Code
CF :
http://codeforces.com/contest/280/submission/3277817本题
#include<cstdio>
#include<cmath>
#include<algorithm>
using namespace std;
const double pi=acos(-1);
int t,l,a;
double x,b;
int main(){
scanf("%d",&t);
while (t--){
scanf("%d%d",&l,&a);
b=(90-a%90)*pi/180;
x=l/(1+sin(b)+cos(b));
//xsinb+x+xcosb=l
printf("%.2f\n",l*l-x*x*sin(2*b));
}
return 0;
}
F 完美数
题目叙述
求[l , r] 中 含 3 || 含 8 - (含 3 && 含 8) 的数字个数。解法:
首先[l , r] = [1 , r] - [1 , l - 1]。因此只要能计算 [ 1 , x ] 即可怎么算呢,这明显是个数位dp,加上状态压缩 —— (0 无3无8 , 1 有3无8 , 2 无3有8 , 3 有3有8)
于是就是个裸的数位dp了。主要看dfs函数,从高位枚举到第i位,状态是s,e代表前i位是否“填满”(比如1234 从千位枚举到各位,枚举到十位时如果是11xy形式那么e = false 如果 是 12xy 形式那么e是True)。如果e的话那么本位最高能枚举到 num[i] 否则能枚举到 9
Code
int f[100][4] , num[100];
int new_s(int s , int d){
if (d == 3) return s | 1;
if (d == 8) return s | 2;
return s;
}
int dfs(int i, int s, bool e) {
if (i==-1) return s==1 || s == 2;
if (!e && ~f[i][s]) return f[i][s];
int res = 0;
int u = e?num[i]:9;
for (int d = 0; d <= u; ++d)
res += dfs(i-1, new_s(s, d), e&&d==u);
return e?res:f[i][s]=res;
}
int gao(int x){
int m = 0;
while(x){
num[ m++ ] = x % 10;
x /= 10;
}
return dfs(m - 1 , 0 , 1);
}
void solve(){
int l , r;
RD(l , r);
OT(gao(r) - gao(l - 1));
}
int main(){
// freopen("0.in" , "r" , stdin);
// freopen("0.out" , "w" , stdout);
FLC(f , -1);
Rush solve();
}
另:
这个题目少年要是写的暴力就太naive了。。
Board:
http://www.acdream.net/contestrank.php?cid=1020
总结:
祝大家玩儿的开心。。
另:
对不起 xlk , 我题目的叙述有很多歧义,感谢您能提出意见并让我耐心改正。