常用技巧合集

1.尺取法

POJ 3061

#include <iostream>
#include <algorithm>
#include<cstring>
#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 <iostream>
#include <algorithm>
#include <map>
#include <set>
#define Max_P 50000
using namespace std;

int P;
int a[Max_P];

void solve() {
    //set储存全部的知识点
    set<int> all;
    for (int i = 0; i < P; ++i) {
        all.insert(a[i]);
    }
    int n = all.size();
    //以下为尺取法
    int s = 0, t = 0, num = 0;
    map<int, int> 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 <iostream>
#include <cstdio>
#include <vector>
#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 <iostream>
#include <cstring>
#include <cstdio>
#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<<i
含有全部n个元素的集合{0,1,.....,n-1}--(1<<n)-1
判断第i个元素是否属于集合S--if(S>>i&1)
向集合中加入第i个元素--S|1<<i
从集合中去除第i个元素--S&~(1<<i)
集合S和T的并集--S|T
集合S和T的交集--S&T


3.相遇碰撞问题

POJ 3684

#include<iostream>
#include "math.h"
#include <algorithm>
#include <iomanip>
#include <string.h>
#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 <<fixed<< setprecision(2) << (y[i] + 2 * R*i / 100.0) << " ";
    }
    cout << endl;
}

int main()
{
    int num;
    cin >> num;
    for (int i = 0; i < num; i++) {
        cin >> N >> H >> R >> T;
        solve();
    }
    return 0;
}

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

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 214,128评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,316评论 3 388
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 159,737评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,283评论 1 287
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,384评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,458评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,467评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,251评论 0 269
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,688评论 1 306
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,980评论 2 328
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,155评论 1 342
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,818评论 4 337
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,492评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,142评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,382评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,020评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,044评论 2 352

推荐阅读更多精彩内容