常用技巧合集

1.尺取法

POJ 3061

#include 
#include 
#include
#define Max_N 50010
using namespace std;

int n, S;
int a[Max_N];
int ans[Max_N];
int ansNum = 0;

void solve() {
    if (S == 0) {
        ans[ansNum++] = 1;
        return;
    }
    int res = n + 1;
    int s = 0, t = 0, sum = 0;
    for (;;) {
        while (t < n&&sum < S)
        {
            sum += a[t++];
        }
        if (sum < S)
            break;
        res = min(res, t-s);
        sum -= a[s++];
    }
    if (res > n)
        res = 0;
    ans[ansNum++] = res;
}

int main()
{
    int cases;
    cin >> cases;
    while (cases>0)
    {
        cases--;
        cin>> n >> S;
        memset(a, 0, n);
        for (int i = 0; i < n; ++i) {
            cin >> a[i];
        }
        solve();
    }
    for (int i = 0; i < ansNum; i++) {
        cout << ans[i] << endl;
    }
    return 0;
}

POJ3320

#include 
#include 
#include 
#include 
#define Max_P 50000
using namespace std;

int P;
int a[Max_P];

void solve() {
    //set储存全部的知识点
    set all;
    for (int i = 0; i < P; ++i) {
        all.insert(a[i]);
    }
    int n = all.size();
    //以下为尺取法
    int s = 0, t = 0, num = 0;
    map count;
    int res = P;
    for (;;) {
        while (t < P&&num < n) {
            if (count[a[t++]]++ == 0) {
                num++;//出现新的知识点
            }
        }
        if (num < n)
            break;
        res = min(res, t - s);
        if (--count[a[s++]] == 0) {
            //出现新的知识点
            num--;
        }
    }
    cout << res << endl;
}

int main()
{
    cin >> P;
    for (int i = 0; i < P; ++i) {
        cin >> a[i];
    }
    solve();
    return 0;
}

POJ 2739

#include "stdafx.h"
#pragma warning(disable:4996)
#include 
#include 
#include 
#define Max_N 100000
using namespace std;
int n;
int ans[Max_N];
int ansNum = 0;
int prime[Max_N];
bool is_Prime[Max_N];

void calculate_primes() {
    int p = 0;
    for (int i = 2; i < 10000; ++i) {
        is_Prime[i] = true;
    }
    is_Prime[0] = is_Prime[1] = false;
    for (int i = 2; i <= 10000; ++i) {
        if (is_Prime[i])
        {
            prime[p++] = i;
            for (int k = i * 2; k <= 10000; k += i) {
                is_Prime[k] = false;
            }
        }
    }
}

void solve() {
    int number = 0;
    int s = 0, t = 0, sum = 0;
    int end = 0;
    for (; n >= prime[end]; end++) {}
    for (int i = 0; i < end; i++) {
    while (sum < n&&t < end) {
            sum += prime[t++];
        }
        if (sum < n) {
            break;
        }
        while (sum > n&&s < t) {
            sum -= prime[s++];
        }
        if (sum == n) {
            number++;
            sum -= prime[s++];
        }
    }
    ans[ansNum++] = number;
}

int main()
{
    calculate_primes();
    while (scanf("%d",&n))
    {
        if (n == 0) {
            break;
        }
        solve();
    }
    for (int i = 0; i < ansNum; i++)
    {
        cout << ans[i] << endl;
    }
    return 0;
}

2.反转问题

POJ 3276

#include 
#include 
#include 
#define MAX_N 5050
using namespace std;

int N;
string Flip;
int dir[MAX_N];//牛的方向,0为正向,1为反向
int f[MAX_N];//区间[i,i+k-1]是否进行反转


//固定K,求对应最小操作数
//无解的话返回-1
int calc(int K) {
    memset(f, 0, sizeof(f));
    int res = 0;//操作数
    int sum = 0;//在这头牛上操作数的和,若为奇数,则此牛的方向与初始方向相反
    for (int i = 0; i + K <= N; ++i) {
        //计算区间i,i+K-1
        if ((dir[i] + sum) % 2 != 0) {
            res++;
            //即前端的牛面朝后方
            f[i] = 1;//进行一次反转
        }
        sum += f[i];
        if (i - K + 1 >= 0) {
            sum -= f[i - K + 1];
        }
    }
    //检查后面的是否有向后的情况,如果有,则无解,返回-1
    for (int i = N - K + 1; i < N; ++i) {
        if ((dir[i] + sum) % 2 != 0) {
            return -1;
        }
        if (i - K + 1 >= 0) {
            sum -= f[i - K + 1];
        }
    }
    return res;
}

void solve() {
    int K = 1, M = N;
    for (int k = 1; k <= N; k++) {
        int m = calc(k);
        if (m >= 0 && M > m) {
            M = m;
            K = k;
        }
    }
    cout << K << " " << M << endl;
}

int main()
{
    char input;
    cin >> N;
    for (int i = 0; i < N; ++i) {
        cin >> input;
        if (input == 'F')
            dir[i] = 0;
        else
            dir[i] = 1;
    }
    solve();
    return 0;
}

集合的整数表示
空集--0
只有第i个元素的集合{i}--1< 含有全部n个元素的集合{0,1,.....,n-1}--(1< 判断第i个元素是否属于集合S--if(S>>i&1)
向集合中加入第i个元素--S|1< 从集合中去除第i个元素--S&~(1< 集合S和T的并集--S|T
集合S和T的交集--S&T


3.相遇碰撞问题

POJ 3684

#include
#include "math.h"
#include 
#include 
#include 
#define MAX_N 200
using namespace std; 


const double g = 10.0;//重力加速度
int N, H, R, T;
double y[MAX_N];

double calc(int T) {
    if (T < 0)
        return H;
    double t = sqrt(2 * H / g);
    int k = (int)(T / t);
    if (k % 2 == 0) {
        double d = T - k * t;
        return H - g * d*d / 2;
    }
    else {
        double d = k * t + t - T;
        return H - g * d*d / 2;
    }
}

void solve() {
    memset(y, 0, sizeof(y));
    for (int i = 0; i < N; ++i) {
        y[i] = calc(T - i);
    }
    sort(y, y + N);
    for (int i = 0; i < N; ++i) {
        cout <> num;
    for (int i = 0; i < num; i++) {
        cin >> N >> H >> R >> T;
        solve();
    }
    return 0;
}

类似的如蚂蚁相遇,由于相遇前速度相同,相遇后两者速度不变,方向相反,可以看作没有碰撞,两个球可以看作相互穿过。

你可能感兴趣的:(常用技巧合集)