模板

最长公共子序列
const int N = 1010;
int a[N][N];

int LCS(const char *s1, const char *s2)
{   //  s1:0...m, s2:0...n
    int m = (int)strlen(s1), n = (int)strlen(s2);
    int i, j;
    a[0][0] = 0;
    for (i = 1; i <= m; ++i)
    {
        a[i][0] = 0;
    }
    for (i = 1; i <= n; ++i)
    {
        a[0][i] = 0;
    }
    for (i = 1; i <= m; ++i)
    {
        for (j = 1; j <= n; ++j)
        {
            if (s1[i - 1] == s2[j - 1])
            {
                a[i][j] = a[i - 1][j - 1] + 1;
            }
            else if (a[i - 1][j] > a[i][j - 1])
            {
                a[i][j]= a[i - 1][j];
            }
            else
            {
                a[i][j] = a[i][j - 1];
            }
        }
    }
    return a[m][n];
}
最长上升子序列
const int maxn = 100010;
int arr[maxn], dp[maxn];
int n, res;

int main()
{
    while (cin >> n&&n != 0)
    {
        res = -1;
        for (int i = 0; i < n; i++)
            cin >> arr[i];
        memset(dp, 0, sizeof(dp));
        for (int i = 0; i < n; i++)
        {
            dp[i] = 1;
            for (int j = 0; j < i; j++)
            {
                if (arr[i] > arr[j])
                    dp[i] = max(dp[i], dp[j] + 1);
            }
            res = max(res, dp[i]);
        }
        cout << res << endl;
    }

}

const int maxn = 100010;
int arr[maxn], d[maxn];
int n, res, pos;

int main()
{
    while (cin >> n&&n != 0)
    {
        res = -1, pos = 0;
        for (int i = 0; i < n; i++)
            cin >> arr[i];
        d[0] = 0;
        for (int i = 0; i < n; i++)
        {
            if (arr[i] > d[pos])
            {
                d[++pos] = arr[i];
            }
            else
                *lower_bound(d, d + pos, arr[i]) = arr[i];
        }   
        cout << pos<< endl;
    }

}
最长递增公共子序列
const int N = 1010;
int f[N][N], dp[N];
int gcis(int a[], int la, int b[], int lb, int ans[])
{   //  a[1...la], b[1...lb]
    int i, j, k, mx;
    memset(f, 0, sizeof(f));
    memset(dp, 0, sizeof(dp));
    for (i = 1; i <= la; i++)
    {
        memcpy(f[i], f[i-1], sizeof(f[0]));
        for (k = 0, j = 1; j <= lb; j++)
        {
            if (b[j - 1] < a[i - 1] && dp[j] > dp[k])
            {
                k = j;
            }
            if (b[j - 1] == a[i - 1] && dp[k] + 1 > dp[j])
            {
                dp[j] = dp[k] + 1,
                f[i][j] = i * (lb + 1) + k;
            }
        }
    }
    for (mx = 0, i = 1; i <= lb; i++)
    {
        if (dp[i] > dp[mx])
        {
            mx = i;
        }
    }
    for (i = la * lb + la + mx, j = dp[mx]; j; i = f[i / (lb + 1)][i % (lb + 1)], j--)
    {
        ans[j - 1] = b[i % (lb + 1) - 1];
    }
    return dp[mx];
}
求最长回文串
const int maxn=1100;
string str;
int m,k,Max,j,start,cnt,x,y;
int p[maxn];
char ch[maxn];

int main()
{
    int Case=0;
    while(cin>>k)
    {
        getchar();
        getline(cin,str);
        memset(p,0,sizeof(p));
        Max=m=0;
       // cout<<str.length()<<"!! "<<endl;
        for(int i=0;i<str.length();i++)
        {
            if(isalpha(str[i]))
            {
                p[m]=i;
                ch[m++]=tolower(str[i]);
            }
        }

        for(int i=0;i<m;i++)
        {
            cnt=0;
            for(j=0;i-j>=0&&i+j<m;j++)//为奇数的情况
            {
                if(ch[i-j]!=ch[i+j])
                    cnt++;
                if(cnt>k)
                    break;
            }
            j--;
            if(p[j+i]-p[i-j]+1>Max)
            {
                Max=p[j+i]-p[i-j]+1;
                start=p[i-j];
            }

            cnt=0;
            for(j=0;i-j>=0&&i+j+1<m;j++)//为偶数的情况
            {
                if(ch[i-j]!=ch[i+j+1])
                    cnt++;
                if(cnt>k)
                    break;
            }
            j--;
            if(j<=-1)//判断特殊情况
                continue;
            if(p[j+i+1]-p[i-j]+1>Max)
            {
                Max=p[j+i+1]-p[i-j]+1;
                start=p[i-j];
            }
        }
        cout<<"Case "<<++Case<<": "<<Max<<" "<<start+1<<endl;
    }
}
最大子段和
const int maxn = 100010;
int arr[maxn], dp[maxn];
int t, n, a, res;
int main()
{
    cin >> t;
    int num = t;
    int Case = 0;
    while (t--)
    {
        int Max, start, lst, fst, n;
        lst = fst = start = 1;
        cin >> n;
        for (int i = 1; i <= n; i++)
            cin >> dp[i];
        Max = dp[1];
        for (int i = 2; i <= n; i++)
        {
            if (dp[i - 1] >= 0)
            {
                dp[i] = dp[i - 1] + dp[i];
            }
            else
                start = i;
            if (dp[i] > Max)
            {
                fst = start;//更新起始位置
                lst = i;
                Max = dp[i];
            }
        }
        cout << "Case " << ++Case << ":\n";
        cout << Max << " " << fst << " " << lst << ((Case == num) ? "\n" : "\n\n");
    }
}
最长有序子序列
/*
 *  递增(默认)
 *  递减 
 *  非递增
 *  非递减 (1)>= && <  (2)<  (3)>=
 */
const int MAXN = 1001;
int a[MAXN], f[MAXN], d[MAXN];   //  d[i] 用于记录 a[0...i] 以 a[i] 结尾的最大长度
int bsearch(const int *f, int size, const int &a)
{
    int l = 0, r = size - 1;
    while (l <= r)
    {
        int mid = (l + r) / 2;
        if (a > f[mid - 1] && a <= f[mid])  //  (1)
        {
            return mid; 
        }
        else if (a < f[mid]){
            r = mid - 1;
        }
        else{
            l = mid + 1;
        }
    }
    return -1;
}
int LIS(const int *a, const int &n)
{
    int i, j, size = 1;
    f[0] = a[0];
    d[0] = 1;
    for (i = 1; i < n; ++i)
    {
        if (a[i] <= f[0])               //  (2)
        {
            j = 0;
        }
        else if (a[i] > f[size - 1])    //  (3)
        {
            j = size++;
        }
        else
        {
            j = bsearch(f, size, a[i]);
        }
        f[j] = a[i];
        d[i] = j + 1;
    }
    return size;
}

int main()
{
    int i, n;
    while (scanf("%d", &n) != EOF)
    {
        for (i = 0; i < n; ++i)
        {
            scanf("%d", &a[i]);
        }
        printf("%d\n", LIS(a, n));      // 求最大递增 / 上升子序列(如果为最大非降子序列,只需把上面的注释部分给与替换)
    }
    return 0;
}
0-1背包问题
const int maxn = 100;
int vis[maxn], d[maxn],f[maxn][maxn];
int v[maxn], w[maxn];
int n, c;
int main()
{
    int v, w;
    cin >> n>>c;
    for (int i = 1; i <= n; i++)
    {
        cin >> v >> w;
        for (int j = 0; j <= c; j++)
        {
            f[i][j] = (i == 1 ? 0 : f[i - 1][j]);
            if (j >= v)
                f[i][j] = max(f[i][j], f[i - 1][j-v] + w);
        }
    }
    cout << f[n][c] << endl;
    system("pause");
}

const int maxn = 100;
int v[maxn], w[maxn];
int d[maxn][maxn];
int main()
{
    int n, c;
    cin >> n >> c;
    for (int i = 1; i <= n; i++)
        cin >> v[i] >> w[i];
    for (int i = n; i >= 1; i--)
    {
        for (int j = 0; j <= c; j++)
        {
            d[i][j] = (i == n ? 0 : d[i+1][j]);
            if (j >= v[i])
            {
                d[i][j] = max(d[i][j], d[i + 1][j - v[i]] + w[i]);
            }
        }
    }
    cout << d[1][c] << endl;
    system("pause");
}

const int maxn = 100;
int f[maxn];
int n, c;
int main()
{
    int v, w;
    memset(f,0,sizeof(f));
    cin >> n>>c;
    for (int i = 1; i <= n; i++)
    {
        cin >> v >> w;
        for(int j=c;j>=0;j--)
        {
            if(j>=v)
                f[j]=max(f[j],f[j-v]+w);
        }       
    }
    cout << f[c] << endl;
    system("pause");
}
多重背包
const int maxn = 110;
int n, m;
int dp[maxn], p[maxn], h[maxn], c[maxn];
void CompleteBack(int v, int w)
{
    for (int i=v; i <= n; i++)
    {
        dp[i] = max(dp[i], dp[i - v] + w);
    }
}

void OnePack(int v, int w)
{
    for (int i = n; i >= v; i--)
    {
        dp[i] = max(dp[i], dp[i - v] + w);
    }
}

int main()
{
    int C, k = 1, count = 0;
    cin >> C;
    while (C--)
    {
        cin >> n >> m;//经费 种类
        memset(dp, 0, sizeof(dp));
        for (int i = 1; i <= m; i++)
        {
            cin >> p[i] >> h[i] >> c[i];//价格 重量 数量
            if (p[i] * c[i] >= n)
                CompleteBack(p[i], h[i]);//完全背包
            else
            {   
                for (int j = 1; j <=c[i]; (j<< 1))
                {
                    OnePack(j*p[i], j*h[i]);//0-1背包
                    c[i] = c[i] - j;
                }
                OnePack(p[i] * c[i], h[i] * c[i]);              
            }
        }
        cout << dp[n] << endl;
    }   
}
物品无限背包问题
const int maxn = 100;
int vis[maxn], d[maxn];
int v[maxn], w[maxn];
int n, c;
int dp(int c)
{
    int &ans = d[c];
    if (ans != -1)
        return ans;
    ans = -(1 << 20);
    for (int i = 0; i < n; i++)
    {
        if (c >= v[i])
        {
            ans = max(ans, dp(c - v[i]) + w[i]);
        }
    }
    return ans;
}
int main()
{
    cin >> n>>c;
    for (int i = 0; i < n; i++)
        cin >> v[i] >> w[i];
    memset(d, -1, sizeof(d));
    d[0] = 0;
    cout<<dp(c);
    system("pause");
}
选择m个子序列且不相交的最大和
int T, n, m, x;  
int z[1000005];  
LL dp[1000005];  
LL dp2[1000005];  
LL ans;  
int main()  
{  
    scanf("%d", &T);  
    while (T--)  
    {  
        scanf("%d %d", &m, &n);  
        for (int i = 1; i <= n; ++i)  
        {  
            scanf("%d", &z[i]);  
        }  
        memset(dp, 0, sizeof(dp));  
        memset(dp2, 0, sizeof(dp2));  
        dp[0] = dp2[0] = 0;  
        for (int i = 1; i <= m; ++i)  
        {  
            ans = -0x7f7f7f7f;  
            for (int j = i; j <= n; ++j)  
            {   
                dp[j] = max(dp[j - 1], dp2[j - 1]) + z[j];  
                dp2[j - 1] = ans;  
                ans = max(dp[j], ans);  
            }  
        }  
        printf("%lld\n", ans);  
    }  
}  
使序列有序交换最少次数

如果只是交换相邻两数,那么最少交换次数为该序列的逆序数。

交换任意两数
/*
 *  交换任意两数的本质是改变了元素位置,
 *  故建立元素与其目标状态应放置位置的映射关系
 */
int getMinSwaps(vector<int> &A)
{
    //  排序
    vector<int> B(A);
    sort(B.begin(), B.end());
    map<int, int> m;
    int len = (int)A.size();
    for (int i = 0; i < len; i++)
    {
        m[B[i]] = i;    //  建立每个元素与其应放位置的映射关系
    }

    int loops = 0;      //  循环节个数
    vector<bool> flag(len, false);
    //  找出循环节的个数
    for (int i = 0; i < len; i++)
    {
        if (!flag[i])
        {
            int j = i;
            while (!flag[j])
            {
                flag[j] = true;
                j = m[A[j]];    //  原序列中j位置的元素在有序序列中的位置
            }
            loops++;
        }
    }
    return len - loops;
}

vector<int> nums;

int main()
{
    nums.push_back(1);
    nums.push_back(2);
    nums.push_back(4);
    nums.push_back(3);
    nums.push_back(5);

    int res = getMinSwaps(nums);

    cout << res << '\n';

    return 0;
}

交换任意区间
/*
 *  默认目标映射关系是 key 1 => val 1 …… key n => val n
 *  如果序列不是 1~n 可以通过 map 建立新的目标映射关系
 *  交换任意区间的本质是改变了元素的后继,故建立元素与其初始状态后继的映射关系
 */
const int MAXN = 30;

int n;
int vis[MAXN];
int A[MAXN], B[MAXN];

int getMinSwaps()
{
    memset(vis, 0, sizeof(vis));

    for (int i = 1; i <= n; i++)
    {
        B[A[i]] = A[i % n + 1];
    }
    for (int i = 1; i <= n; i++)
    {
        B[i] = (B[i] - 2 + n) % n + 1;
    }

    int cnt = n;
    for (int i = 1; i <= n; i++)
    {
        if (vis[i])
        {
            continue;
        }
        vis[i] = 1;
        cnt--;
        for (int j = B[i]; j != i; j = B[j])
        {
            vis[j] = 1;
        }
    }

    return cnt;
}

int main()
{
    cin >> n;
    for (int i = 1; i <= n; i++)
    {
        cin >> A[i];
    }

    int res = getMinSwaps();

    cout << res << '\n';

    return 0;
}
给出n个数和Q个询问(l,r),对于每个询问求出(l,r)之间连续出现次数最多的次数。

/*
 *  求区间中数出现的最大频率
 *  方法一:线段树.
 *  先离散化。因为序列是升序,所以先将所有值相同的点缩成一点。这样n规模就缩小了。建立一个数据结构
 *  记录缩点的属性:在原序列中的值id,和该值有多少个num比如序列
 *  10
 *  -1 -1 1 1 1 1 3 10 10 10
 *  缩点后为:下标 1 2 3 4
 *          id -1 1 3 10
 *         num  2 4 1 3
 *  然后建树,树的属性有区间最大值(也就是频率)和区间总和。
 *  接受询问的时候。接受的是原来序列的区间[be,ed]我们先搜索一下两个区间分别在离散化区间后的下标。
 *  比如接受[2,3]时候相应下标区间就是[1,2];[3,10]的相应下标区间是[2,4];
 *  处理频率的时候,我们发现两个极端,也就是左右两个端点的频率不好处理。因为它们是不完全的频率
 *  也就是说有部分不在区间内。但是如果对于完全区间,也就是说左右端点下标值完全在所求区间内。
 *  比如上例的[2,3]不好处理。但是如果是[1,6],或是[1,10]就很好处理了,只要像RMQ一样询问区间最大值就可以了。
 *  方法二:RMQ. 
 *  我们可以转化一下问题。将左右端点分开来考虑。
 *  现在对于离散后的询问区间我们可以分成3个部分.左端点,中间完全区间,右端点。
 *  对于中间完全区间线段树或RMQ都能轻松搞定。只要特判一左右的比较一下就得最后解了。
 */
int build(int a, int b);
int query(int index, int a, int b);

const int N = 100010;

struct NODE
{
    int b, e;   //  区间[b, e]
    int l, r;   //  左右子节点下标
    int number; //  区间内的最大频率值
    int last;   //  以 data[e]结尾且与 data[e]相同的个数:data[e-last+1]...data[e]
} node[N * 2 + 1];

int len, data[N];

int main()
{
    int n;
    while (scanf("%d", &n), n)
    {
        int i, q, a, b;
        scanf("%d", &q);
        for (i = 0; i < n; i++)
        {
            scanf("%d", &data[i]);
        }
        len = 0;    //  下标
        build(0, n - 1);
        while (q--)
        {
            scanf("%d%d", &a, &b);
            printf("%d\n", query(0, a - 1, b - 1)); //  输出区间的最大频率值,而非data[]
        }
    }
    return 0;
}

int build(int a, int b) //  建立线段树
{
    int temp = len, mid = (a + b) / 2;
    node[temp].b = a, node[temp].e = b;
    len++;
    if (a == b)
    {
        node[temp].number = 1;
        node[temp].last = 1;
        return temp;
    }
    node[temp].l = build(a, mid);
    node[temp].r = build(mid + 1, b);
    int left_c = node[temp].l, right_c = node[temp].r, p, lcount = 0, rcount = 0, rec, max = 0;
    rec = data[mid];
    p = mid;
    while (p >= a && data[p] == rec)
    {
        p--, lcount++;
    }
    node[left_c].last = lcount;
    rec = data[mid + 1];
    p = mid + 1;
    while (p <= b && data[p] == rec)
    {
        p++, rcount++;
    }
    node[right_c].last = rcount;
    if (data[mid] == data[mid + 1])
    {
        max = lcount + rcount;
    }
    if (node[left_c].number > max)
    {
        max = node[left_c].number;
    }
    if (node[right_c].number > max)
    {
        max = node[right_c].number;
    }
    node[temp].number = max;
    return temp;
}

int query(int index, int a, int b)
{
    int begin = node[index].b;
    int end = node[index].e;
    int mid = (begin + end) / 2;
    if (a == begin && b == end)
    {
        return node[index].number;
    }
    if (a > mid)
    {
        return query(node[index].r, a, b);
    }
    if (b < mid + 1)
    {
        return query(node[index].l, a, b);
    }
    int temp1, temp2, max;
    if (node[index].l > 0)
    {
        temp1 = query(node[index].l, a, mid);
    }
    if (node[index].r > 0)
    {
        temp2 = query(node[index].r, mid + 1, b);
    }
    max = temp1 > temp2 ? temp1 : temp2;
    if (data[mid] != data[mid + 1])
    {
        return max;
    }
    temp1 = node[node[index].l].last > (mid - a + 1) ? (mid - a + 1) : node[node[index].l].last;
    temp2 = node[node[index].r].last > (b - mid) ? (b - mid) : node[node[index].r].last;
    if (max < temp1 + temp2)
    {
        max = temp1 + temp2;
    }
    return max;
}
机器工作调度
2台机器,n件任务,必须先在S1上做,再在S2上做. 
任务之间先做后做任意.求最早的完工时间. 
这是一个经典问题: 2台机器的情况下有多项式算法(Johnson算法),3台或以上的机器是NP-hard算法。
Johnson算法: 
(1)把作业按工序加工时间分成两个子集,第一个集合中在S1上做的时间比在S2上少,其它的作业放到第二个集合; 
  先完成第一个集合里面的作业,再完成第二个集合里的作业. 
(2)对于第一个集合,其中的作业顺序是按在S1上的时间的不减排列; 
  对于第二个集合, 其中的作业顺序是按在S2上的时间的不增排列.
const int MAXN = 5e4 + 5;

struct task
{
    int a;
    int b;
} TaskA[MAXN], TaskB[MAXN];

bool cmpA(task a, task b)
{
    return a.a <= b.a;
}
bool cmpB(task a, task b)
{
    return a.b >= b.b;
}
int main(int argc, const char * argv[])
{
    int N;
    cin >> N;

    int a, b;
    int posA = 0, posB = 0;
    int sumA = 0, sumB = 0;
    for (int i = 0; i < N; i++)
    {
        scanf("%d %d", &a, &b);
        if (a < b)
        {
            TaskA[posA].a = a;
            TaskA[posA++].b = b;
            sumA += b;
        }
        else
        {
            TaskB[posB].a = a;
            TaskB[posB++].b = b;
            sumB += a;
        }
    }
    sort(TaskA, TaskA + posA, cmpA);
    sort(TaskB, TaskB + posB, cmpB);

    for (int i = 0; i < posB; i++)
    {
        TaskA[posA++] = TaskB[i];
    }

    int ans = TaskA[0].a + TaskA[0].b;
    int sum = TaskA[0].a;
    for (int i = 1; i < posA; i++)
    {
        sum += TaskA[i].a;
        ans = sum < ans ? ans + TaskA[i].b : sum + TaskA[i].b;
    }

    cout << ans << '\n';
    return 0;
}
带权值的并查集
const int N = 1010;

struct lset
{
    int p[N], rank[N], sz;
    void link(int x, int y)
    {
        if (x == y)
        {
            return ;
        }
        if (rank[x] > rank[y])
        {
            p[y] = x;
        }
        else
        {
            p[x] = y;
        }
        if (rank[x] == rank[y])
        {
            rank[y]++;
        }
        return ;
    }
    void makeset(int n)
    {
        sz = n;
        for (int i = 0; i < sz; i++)
        {
            p[i] = i;
            rank[i] = 0;
        }
        return ;
    }
    int findset(int x)
    {
        if (x != p[x])
        {
            p[x] = findset(p[x]);
        }
        return p[x];
    }
    void unin(int x, int y)
    {
        link(findset(x), findset(y));
        return ;
    }
    void compress()
    {
        for (int i = 0; i < sz; i++)
        {
            findset(i);
        }
        return ;
    }
};
拓扑排序
/*
 *  拓扑排序
 *  INIT:edge[][]置为图的邻接矩阵;cnt[0...i...n-1]:顶点i的入度。
 */
const int MAXV = 1010;

int edge[MAXV][MAXV];
int cnt[MAXV];

void TopoOrder(int n)
{
    int i, top = -1;
    for (i = 0; i < n; ++i)
    {
        if (cnt[i] == 0)
        {   //  下标模拟堆栈
            cnt[i] = top;
            top = i;
        }
    }
    for (i = 0; i < n; i++)
    {
        if (top == -1)
        {
            printf("存在回路\n");
            return ;
        }
        else
        {
            int j = top;
            top = cnt[top];
            printf("%d", j);
            for (int k = 0; k < n; k++)
            {
                if (edge[j][k] && (--cnt[k]) == 0)
                {
                    cnt[k] = top;
                    top = k;
                }
            }
        }
    }
}
星期问题
/*
 *  已知1752年9月3日是Sunday,并且日期控制在1700年2月28日后
 */
char name[][15] = { "monday", "tuesday", "wednesday", "thursday", "friday", "saturday", "sunday"};

int main()
{
    int d, m, y, a;
    printf("Day: ");
    scanf("%d", &d);
    printf("Month: ");
    scanf("%d", &m);
    printf("Year: ");
    scanf("%d", &y);
    //  1月2月当作前一年的13,14月
    if (m == 1 || m == 2)
    {
        m += 12;
        y--;
    }
    //  判断是否在1752年9月3日之前,实际上合并在一起倒更加省事
    if ((y < 1752) || (y == 1752 && m < 9) || (y == 1752 && m == 9 && d < 3))
    {
        //  因为日期控制在1700年2月28日后,所以不用考虑整百年是否是闰年
        a = (d + 2 * m + 3 * (m + 1) / 5 + y + y / 4 + 5) % 7;
    }
    else
    {
        //  这里需要考虑整百年是否是闰年的情况
        a = (d + 2 * m + 3 * (m + 1) / 5 + y + y / 4 - y / 100 + y / 400) % 7;  //  实际上这个可以当做公式背下来
    }
    printf("it's a %s\n", name[a]);
    return 0;
}
多项式求根(牛顿法)
/* 
 *  牛顿法解多项式的根
 *  输入:多项式系数c[],多项式度数n,求在[a,b]间的根
 *  输出:根 要求保证[a,b]间有根
 */

double fabs(double x)
{
    return (x < 0) ? -x : x;
}

double f(int m, double c[], double x)
{
    int i;
    double p = c[m];
    for (i = m; i > 0; i--)
    {
        p = p * x + c[i - 1];
    }
    return p;
}

int newton(double x0, double *r, double c[], double cp[], int n, double a, double b, double eps)
{
    int MAX_ITERATION = 1000;
    int i = 1;
    double x1, x2, fp, eps2 = eps / 10.0;
    x1 = x0;
    while (i < MAX_ITERATION)
    {
        x2 = f(n, c, x1);
        fp = f(n - 1, cp, x1);
        if ((fabs(fp) < 0.000000001) && (fabs(x2) > 1.0))
        {
            return 0;
        }
        x2 = x1 - x2 / fp;
        if (fabs(x1 - x2) < eps2)
        {
            if (x2 < a || x2 > b)
            {
                return 0;
            }
            *r = x2;
            return 1;
        }
        x1 = x2;
        i++;
    }
    return 0;
}

double Polynomial_Root(double c[], int n, double a, double b, double eps)
{
    double *cp;
    int i;
    double root;
    cp = (double *)calloc(n, sizeof(double));
    for (i = n - 1; i >= 0; i--)
    {
        cp[i] = (i + 1) * c[i + 1];
    }
    if (a > b)
    {
        root = a;
        a = b;
        b = root;
    }
    if ((!newton(a, &root, c, cp, n, a, b, eps)) && (!newton(b, &root, c, cp, n, a, b, eps)))
    {
        newton((a + b) * 0.5, &root, c, cp, n, a, b, eps);
    }
    free(cp);
    if (fabs(root) < eps)
    {
        return fabs(root);
    }
    else
        return root;
}
1/n循环节长度
/*
 *  求1/i的循环节长度的最大值,i<=n
 */

const int MAXN = 1005;

int res[MAXN];  //  循环节长度

int main()
{
    memset(res, 0, sizeof(res));

    int i, temp, j, n;

    for (temp = 1; temp <= 1000; temp++)
    {
        i = temp;
        while (i % 2 == 0)
        {
            i /= 2;
        }
        while (i % 5 == 0)
        {
            i /= 5;
        }
        n = 1;
        for (j = 1; j <= i; j++)
        {
            n *= 10;
            n %= i;
            if (n == 1)
            {
                res[temp] = j;
                break;
            }
        }
    }

    int max_re;

    while (cin >> n)
    {
        max_re = 1;
        for (i = 1; i <= n; i++)
        {
            if (res[i] > res[max_re])
            {
                max_re = i;
            }
        }
        cout << max_re << endl;
    }
    return 0;
}
A^B约数之和对MOD取模
/*
 *  求A^B的约数之和对MOD取模
 *  需要素数筛选和合数分解的算法,需要先调用getPrime();
 *  参考《合数相关》
 *  1+p+p^2+p^3+...+p^n
 */
const int MOD = 1000000;

long long pow_m(long long a, long long n)
{
    long long ret = 1;
    long long tmp = a % MOD;
    while(n)
    {
        if (n & 1)
        {
            ret = (ret * tmp) % MOD;
        }
        tmp = tmp * tmp % MOD;
        n >>= 1;
    }
    return ret;
}

//  计算1+p+p^2+...+p^n
long long sum(long long p, long long n)
{
    if (p == 0)
    {
        return 0;
    }
    if (n == 0)
    {
        return 1;
    }
    if (n & 1)
    {
        return ((1 + pow_m(p, n / 2 + 1)) % MOD * sum(p, n / 2) % MOD) % MOD;
    }
    else
    {
        return ((1 + pow_m(p, n / 2 + 1)) % MOD * sum(p, n / 2 - 1) + pow_m(p, n / 2) % MOD) % MOD;
    }
}

//  返回A^B的约数之和%MOD
long long solve(long long A, long long B)
{
    getFactors(A);
    long long ans = 1;
    for (int i = 0; i < fatCnt; i++)
    {
        ans *= sum(factor[i][0], B * factor[i][1]) % MOD;
        ans %= MOD;
    }
    return ans;
}
约瑟夫环问题的原来描述为,设有编号为01,……,n-1的n(n>0)个人围成一个圈,从第1个人开始报数,报到m时停止报数,报m的人出圈,再从他的下一个人起重新报数,报到m时停止报数,报m的出圈,……,如此下去,直到所有人全部出圈为止。当任意给定n和m后,设计算法求n个人出圈的次序。
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
int n,m,k;
int main()
{
    while (scanf("%d%d",&n,&m))//编号0,1,2,3,.....,n-1 
    {       
        int s=0;//只有一个人时最后出圈的人编号为0 
        for (int i=2;i<=n;i++)
            s=(s+m)%i;

        printf("%d\n",s);//编号为s的最后出圈 
    }
    return 0;
}

打印出圈顺序
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;

int n, m, k, p, num, step;
int arr[20];

int main()
{
    scanf("%d%d", &n, &m);//人数 步数 
    for (int i = 1; i <= n; i++)
    {
        arr[i] = i;
    }

    p = n;//从位置n开始数m个位置不包括位置n
    num = n;//人数num
    step = m;//步数step
    while (num)
    {
        while (step--)
        {
            do {
                p = (p + n) %n  + 1;        
            } while (arr[p] == 0);//走到下个未出圈的位置
        }
        printf("%d ", p);
        step = m;
        num--;
        arr[p] = 0;//出圈
    }
    system("pause");
    return 0;
}
set基本操作
s.begin()       //  返回指向第一个元素的迭代器
s.clear()       //  清除所有元素
s.count()       //  返回某个值元素的个数
s.empty()       //  如果集合为空,返回true(真)
s.end()         //  返回指向最后一个元素之后的迭代器,不是最后一个元素
s.equal_range() //  返回集合中与给定值相等的上下限的两个迭代器
s.erase()       //  删除集合中的元素
s.find()        //  返回一个指向被查找到元素的迭代器
s.get_allocator()   //  返回集合的分配器
s.insert()      //  在集合中插入元素
s.lower_bound() //  返回指向大于(或等于)某值的第一个元素的迭代器
s.key_comp()    //  返回一个用于元素间值比较的函数
s.max_size()    //  返回集合能容纳的元素的最大限值
s.rbegin()      //  返回指向集合中最后一个元素的反向迭代器
s.rend()        //  返回指向集合中第一个元素的反向迭代器
s.size()        //  集合中元素的数目
s.swap()        //  交换两个集合变量
s.upper_bound() //  返回大于某个值元素的迭代器
s.value_comp()  //  返回一个用于比较元素间的值的函数
vector基本操作
s[i]                //  直接以下标方式访问容器中的元素
s.front()           //  返回首元素
s.back()            //  返回尾元素
s.push_back(x)      //  向表尾插入元素x
s.size()            //  返回表长
s.empty()           //  表为空时,返回真,否则返回假
s.pop_back()        //  删除表尾元素
s.begin()           //  返回指向首元素的随机存取迭代器
s.end()             //  返回指向尾元素的下一个位置的随机存取迭代器
s.insert(it, val)   //  向迭代器it指向的元素前插入新元素val
s.insert(it, n, val)//  向迭代器it指向的元素前插入n个新元素val
s.insert(it, first, last)   
//  将由迭代器first和last所指定的序列[first, last)插入到迭代器it指向的元素前面
s.erase(it)         //  删除由迭代器it所指向的元素
s.erase(first, last)//  删除由迭代器first和last所指定的序列[first, last)
s.reserve(n)        //  预分配缓冲空间,使存储空间至少可容纳n个元素
s.resize(n)         //  改变序列长度,超出的元素将会全部被删除,如果序列需要扩展(原空间小于n),元素默认值将填满扩展出的空间
s.resize(n, val)    //  改变序列长度,超出的元素将会全部被删除,如果序列需要扩展(原空间小于n),val将填满扩展出的空间
s.clear()           //  删除容器中的所有元素
s.swap(v)           //  将s与另一个vector对象进行交换
s.assign(first, last)
//  将序列替换成由迭代器first和last所指定的序列[first, last),[first, last)不能是原序列中的一部分

//  要注意的是,resize操作和clear操作都是对表的有效元素进行的操作,但并不一定会改变缓冲空间的大小
//  另外,vector还有其他的一些操作,如反转、取反等,不再一一列举
//  vector上还定义了序列之间的比较操作运算符(>、<、>=、<=、==、!=),可以按照字典序比较两个序列。
map基本操作
m[key] = value; //  [key]操作是map很有特色的操作,如果在map中存在键值为key的元素对, 则返回该元素对的值域部分,否则将会创建一个键值为key的元素对,值域为默认值。所以可以用该操作向map中插入元素对或修改已经存在的元素对的值域部分。
m.insert(make_pair(key, value));    //  也可以直接调用insert方法插入元素对,insert操作会返回一个pair,当map中没有与key相匹配的键值时,其first是指向插入元素对的迭代器,其second为true;若map中已经存在与key相等的键值时,其first是指向该元素对的迭代器,second为false。

/*  查找元素  */
int i = m[key]; //  要注意的是,当与该键值相匹配的元素对不存在时,会创建键值为key(当另一个元素是整形时,m[key]=0)的元素对。
map<string, int>::iterator it = m.find(key);    //  如果map中存在与key相匹配的键值时,find操作将返回指向该元素对的迭代器,否则,返回的迭代器等于map的end()(参见vector中提到的begin()和end()操作)。

/*  删除元素  */
m.erase(key);   //  删除与指定key键值相匹配的元素对,并返回被删除的元素的个数。
m.erase(it);    //  删除由迭代器it所指定的元素对,并返回指向下一个元素对的迭代器。

/*  其他操作  */
m.size();       //  返回元素个数
m.empty();      //  判断是否为空
m.clear();      //  清空所有元素
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值