0808

快速幂

输入a,b,p;
求a的b次幂对p求余。
把b拆成二进制数,通过位运算得到最低位来巧妙降低复杂度。

int a,b,p;
cin>>a>>b>>p;
int ans = 1;
for(;b;b>>=1)
{
    if(b&1)
        ans = (long long)ans*a%p;
    a = (long long)a*a%p;
}

成对变换

对于非负整数n

  • 若n为偶数,则n^1等于n+1
  • 若n为奇数,则n^1等于n-1

lowbit运算

lowbit(n)定义为非负整数n在二进制表示下“最低位的1及其后边所有的0”构成的数值。

lowbit(n) = n&(-n);

原理:计算机中数值都由补码形式储存,而负数的补码为原码取反加一。假设一个整数0-k-1位都是0,那么他的相反数的补码0-k-1为也都是0,但是第k位为1,k+1之后的与该正数都互为反,所以两者做与运算可以直接求得所求。

奇怪的汉诺塔

三个的汉诺塔的递推公式

f(n) = 2*f(n-1)+1

但是如果是四个(从A到D)的话,就可以先把n个中的前k个放到一个塔上,另外n-k个都是按照三个汉诺塔的来放到第四个(D),然后再将前k个按照四个柱子的方法移到第四个柱子。

d(n) = min(2*d(k)+f(n-k))

其中k < n;

a[1] = 1;
b[1] = 1;
b[0] = 0;
for(int i=2;i<=12;i++)
{
    b[i] = 2*b[i-1]+1;
    a[i] = inf;
    for(int j=1;j<=i;j++)
        a[i] = min(a[i],a[j]*2+b[i-j]);
    
}

前缀和(poj3263)

N头牛,告诉最高的牛高H在p处,然后告诉A可以看到B,可以知道B的高大于等于A的高,A与B之间的牛要比A低

map<pair<int,int>,bool> existed;
int c[10010],d[10010];
int main() 
{
    int n,i,h,r;
    while(cin>>n>>i>>h>>r)
    {
        int a,b;
        for(int i=0;i<r;i++)
        {
            cin>>a>>b;
            if(a>b)swap(a,b);
            if(existed[make_pair(a,b)])continue;
            d[a+1]--;d[b]++;
            existed[make_pair(a,b)] = 1;
        }
        for(int i=1;i<=n;i++)
        {
            c[i] = c[i-1]+d[i];
            printf("%d\n",h+c[i]);
        }
    }
    return 0;
}
  • 输入之后要调整a和b的大小
  • 判重
  • 用另外一个数组记录,然后通过前缀和来表示高度之间的差值(核心)

递归枚举

  • 递归思路是将基本单元缩小

从1-n这n个整数中随机选取任意多个,输出所有可能的方案。

分析

  • 从1-n开始,每个都只有两个选择
  • 对于每两个选择,分别进行后面数字的选择
  • 对于一个数字,做完决策后把痕迹删除
int n;
vector<int> chosen;
void calc(int x)
{
    if(x==n+1)//满足条件即输出
    {
        for(int i=0;i<chosen.size();i++)
        printf("%d ",chosen[i]);
        puts("");//输出完会有回车
        return ;
    }
    calc(x+1);
    chosen.push_back(x);
    calc(x+1);
    chosen.pop_back();//一定要消除痕迹
}
int main() 
{
    while(cin>>n)
        calc(1);
    return 0;
}

递归实现排列型枚举

从1-n 这n(n < 10)个整数排除一行后随机打乱顺序,输出所有可能的次序

  • 先排好n-1,然后对于第n个有选哪个的问题,所以要遍历剩下的
  • 要记录之前选过的,需要一个chosen数组
  • 最后要删除标记
int n;
int order[21];
int chosen[21];
void calc(int k)
{
    if(k==n+1)
    {
        for(int i=1;i<=n;i++)
            printf("%d ",order[i]);
        puts("");
        return;
    }
    for(int i=1;i<=n;i++)
    {
        if(chosen[i])
            continue;
        order[k] = i;
        chosen[i] = 1;
        calc(k+1);
        chosen[i] = 0;
    }
}

int main() 
{
    while(cin>>n)
        calc(1);
    return 0;
}

Fractal Streets(poj3889)

题意不在赘述

递归,从n递归到1,解决最小问题,经过一步一步转化得到n级城市的坐标。

  • 房屋必须要从0开始,因为要方便确定属于哪一个区
  • 在城市升级过程中要格外小心坐标转换
  • 最后计算距离时sqrt的输出
pair<long long,long long> calc(int n,long long m)
{
    if(n==0)
        return make_pair(0,0);
    long long len = 1<<(n-1),cnt = 1<<(2*n-2);
    pair<long long,long long> pos = calc(n-1,m%cnt);
    long long x = pos.first,y = pos.second;
    long long z = m/cnt;
    if(z==0)
        return make_pair(y,x);
    if(z==1)
        return make_pair(x+len,y);
    if(z==2)
        return make_pair(x+len,y+len);
    if(z==3)
        return make_pair(len-y-1,2*len-x-1);
}

int main() 
{
    int t;
    cin>>t;
    while(t--)
    {
        int n;
        long long h,o;
        cin>>n>>h>>o;
        pair<long long,long long>a = calc(n,h-1);
        //cout<<a.first<<a.second<<endl;
        pair<long long,long long>b = calc(n,o-1);
        //cout<<b.first<<b.second<<endl;
        printf("%.0f\n",sqrt((double)(a.first-b.first)*(a.first-b.first)+(double)(a.second-b.second)*(a.second-b.second))*10) ;
        //cout<<dis*10<<endl;
    }
    return 0;
}

总结

  • 今天虽然只看了二十页,有些难题还没有AC,样例过了始终无法AC。
  • 二进制的部分要经常复习
  • 递推和递归条件一开始就要清楚,遇到答案不符的情况可以输出过程量测试找bug
  • 尽量不调试。

猜你喜欢

转载自www.cnblogs.com/1625--H/p/9446036.html
008