noip部分题目总结

6102

天天爱跑步

毒瘤题,神仙树上上差分。
先推出两个式子
\(dep[u] = dep[i] + w[i]\),
\(dep[u] - dep[lca] = w[i] - dep[i]\) 开桶差分。
因为差分会导致统计子树时会有子树外的值,所以要用前缀作差的形式来消除影响。

#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<queue>
#include<set>
#include<vector>
#include<cmath>
using namespace std;
typedef long long ll;
const int maxn = 3e5 + 7;
int n,m;
int l,pre[maxn<<1],last[maxn],other[maxn<<1];
int sum[maxn],tmp[maxn],w[maxn],ans[maxn],dep[maxn];
int f[maxn][20];
int c1[maxn<<1],c2[maxn<<1];
vector <int> a1[maxn],b1[maxn],a2[maxn],b2[maxn];
void add(int x,int y)
{
    l++;
    pre[l] = last[x];
    last[x] = l;
    other[l] = y;
}
void dfs2(int x)
{
    for(int p = last[x];p;p = pre[p])
    {
        int v = other[p];
        if(v == f[x][0])continue;
        dep[v] = dep[x] + 1;
        f[v][0] = x;
        dfs2(v);
    }
}
int lca(int u,int v)
{
    if(dep[u] < dep[v])swap(u,v);
    for(int i = 0;i <= 16;i ++)
    {
        if((dep[u] - dep[v])&(1<<i))u = f[u][i];
    }
    if(u == v)return u;
    for(int i = 17;i >= 0;i --)
    {
        if(f[u][i] != f[v][i])
        {
            u = f[u][i];
            v = f[v][i];
        }
    }
    return f[u][0];
}
void dfs(int x,int fa){
    int cnt1 = c1[dep[x] + w[x]],cnt2 = c2[w[x] - dep[x] + n];
    for(int p = last[x];p;p = pre[p]){
        int v = other[p];
        if(v == fa)continue;
        dfs(v,x);
    }
    for(int i = 0;i < a1[x].size();i ++)c1[a1[x][i]] ++;
    for(int i = 0;i < b1[x].size();i ++)c1[b1[x][i]] --;
    for(int i = 0;i < a2[x].size();i ++)c2[a2[x][i] + n] ++;
    for(int i = 0;i < b2[x].size();i ++)c2[b2[x][i] + n] --;
    ans[x] = c1[dep[x] + w[x]] - cnt1 + c2[w[x] - dep[x] + n] - cnt2;
}
int main()
{
    n = read(),m = read();
    for(int i = 1;i < n ;i ++)
    {
        int u = read(),v = read();
        add(u,v);add(v,u);
    }
    dfs2(1);
    for(int j = 1;j <= 18;j ++){
        for(int i = 1;i <= n ;i ++){
            f[i][j] = f[f[i][j-1]][j-1];
        }
    }
    for(int i = 1;i <= n ;i ++)w[i] = read();
    for(int i = 1;i <= m ;i ++){
        int u = read(),v = read();
        int x = lca(u,v);
        a1[u].push_back(dep[u]);
        b1[f[x][0]].push_back(dep[u]);
        a2[v].push_back(dep[u] - 2*dep[x]);
        b2[x].push_back(dep[u] - 2*dep[x]); 

    }
    dfs(1,0);
    for(int i = 1;i <= n;i ++)cout<<ans[i]<<" ";
    return 0;
}

蚯蚓

发现题目隐藏性质,减低复杂度的关键在于大根堆的log,每次切断都是单调的,便可用三个队列维护。
证明:两条蚯蚓,长度为\(a,b(a > b)\),\(t\)秒后切断\(b\),此时a的两条的长度\(pa + tx,(1-p)x + tx\),\(b\)两条长度\(p(b + t),(1-p)(b + t)\)单调显而易见。

#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<queue>
#include<set>
#include<vector>
#include<cmath>
using namespace std;
typedef long long ll;
const int maxn = 7e6 + 7;
queue <ll> q1,q2,q3;
int n,m,f,u,v,t;
int a[maxn];
ll addtag;
int main()
{
    scanf("%d%d%d%d%d%d",&n,&m,&f,&u,&v,&t);
    double p = (double)u/(double)v;
    for(int i = 1;i <= n;i ++){
        scanf("%d",a + i);
    }
    sort(a + 1,a + 1 + n);
    for(int i = n;i >= 1;i --)
        q1.push(a[i]);
    for(int i = 1;i <= m;i ++){
        ll mx = -1e9,flag = 0;
        if(!q1.empty() && q1.front() > mx) mx = q1.front(),flag = 1;
        if(!q2.empty() && q2.front() > mx) mx = q2.front(),flag = 2;
        if(!q3.empty() && q3.front() > mx) mx = q3.front(),flag = 3;
        if(flag == 1) q1.pop();
        if(flag == 2) q2.pop();
        if(flag == 3) q3.pop();
        if(i % t == 0){
            printf("%lld ",mx + addtag);
        }
        mx += addtag;
        ll x = floor(p * mx);ll y = mx - x;
        x -= addtag;y -= addtag;
        q2.push(x - f);q3.push(y - f);
        addtag += f;
    }
    cout<<endl;
    for(int i = 1;i <= n + m;i ++){
        ll mx = -1e9,flag = 0;
        if(!q1.empty() && q1.front() > mx) mx = q1.front(),flag = 1;
        if(!q2.empty() && q2.front() > mx) mx = q2.front(),flag = 2;
        if(!q3.empty() && q3.front() > mx) mx = q3.front(),flag = 3;
        if(flag == 1) q1.pop();
        if(flag == 2) q2.pop();
        if(flag == 3) q3.pop();
        if(i % t == 0){
            printf("%lld ",mx + addtag);
        }
    }
    return 0;
}

愤怒的小鸟

\(dp\)还是比较好想的,预处理出所有抛物线,\(dp[s | line[i]] = max(dp[s] + 1)\)

#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<queue>
#include<set>
#include<vector>
#include<cmath>
using namespace std;
typedef long long ll;
int n,m,T,ans;
double x[1010],y[1011];
int dp[(1<<18) + 1],line[10101],cnt;
bool calc(int d,double a,double b){
//  cout<<abs(a*x[d]*x[d] + b*x[d] - y[d])<<endl;
    if(fabs(a*x[d]*x[d] + b*x[d] - y[d]) <= 0.000001)return 1;
    return 0;
}
int main()
{
    scanf("%d",&T);
    while(T--){
        scanf("%d%d",&n,&m);
        for(int i = 1;i <= n ;i ++){
            scanf("%lf%lf",&x[i],&y[i]);
        }
        memset(dp,0x3f,sizeof dp);
        dp[0] = 0;
        cnt = 0;
        for(int i = 1;i <= n ;i ++){
            line[++cnt] = (1 << (i-1));
            for(int j = i + 1;j <= n;j ++){
                if(fabs(y[i]/x[i] - y[j]/x[j]) <= 0.0001)continue;
                double a = (x[j]*y[i] - x[i]*y[j])/((x[i]-x[j])*x[i]*x[j]);
                double b = (y[i] - a*x[i]*x[i])/x[i];
                if(a > 0)continue;
                int s = 0;
                for(int k = 1;k <= n ;k ++){
                    if(calc(k,a,b)){
                        s |= (1 << (k-1));
                    }
                }
                line[++cnt] = s;
            }
        }
        for(int s = 0;s < (1 << n);s ++){
            for(int i = 1;i <= cnt;i ++){
                dp[s | line[i]] = min(dp[s] + 1,dp[s|line[i]]);
            }
        }
        printf("%d\n",dp[(1 << n)-1]);
    }
    return 0;
}

换教室
一个期望\(DP\)入门题,\(dp[i][j][0/1]\)表示前\(i\)个改了\(j\)门,第\(i\)门改/没改的期望,转移比较长要仔细写。

#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<queue>
#include<set>
#include<vector>
#include<cmath>
using namespace std;
typedef long long ll;
int read(){
    int x;scanf("%d",&x);return x;
}
const int maxn = 2001;
int n,m,v,e,c[maxn],d[maxn];
double dis[maxn][maxn];
double dp[maxn][maxn][2],k[maxn];
int main()
{
    n = read(),m = read(),v = read(),e = read();
    for(int i = 1;i <= n;i ++)c[i] = read();
    for(int i = 1;i <= n;i ++)d[i] = read();
    for(int i = 1;i <= n;i ++)scanf("%lf",&k[i]);
    for(int i = 1;i <= v;i ++){
        for(int j = 1;j <= v;j ++){
            dis[i][j] = 1e9 + 7;
        }
    }
    for(int i = 1;i <= e;i ++){
        int a = read(),b = read();double w;
        scanf("%lf",&w);
        dis[a][b] = dis[b][a] = min(dis[a][b],w);
    }
    for(int i = 1;i <= v;i ++)dis[i][i] = 0;
    for(int p = 1;p <= v;p ++){
        for(int i = 1;i <= v;i ++){
            for(int j = 1;j <= v;j ++)
            dis[i][j] = min(dis[i][j],dis[i][p]+dis[p][j]);
        }
    }
    for(int i = 0;i <= n ;i ++){
        for(int j = 0 ;j <= m ;j ++){
            dp[i][j][0] = dp[i][j][1] = 1e9 + 7;
        }
    }
    dp[1][0][0] = dp[1][1][1] = 0;
    double ans = 1e9 + 7;
    for(int i = 2;i <= n ;i ++){
        for(int j = 0;j <= min(m,i) ;j ++){
            double p1 = k[i],p2 = 1-k[i],p3 = k[i-1],p4 = 1 - k[i-1];
            dp[i][j][0] = min(dp[i-1][j][0] + dis[c[i-1]][c[i]],dp[i-1][j][1] + dis[d[i-1]][c[i]]*p3 + dis[c[i-1]][c[i]]*p4);
            if(j)
            dp[i][j][1] = min(dp[i-1][j-1][0] + dis[c[i-1]][c[i]]*p2 + dis[c[i-1]][d[i]]*p1,dp[i-1][j-1][1] + dis[c[i-1]][c[i]]*p2*p4 + dis[c[i-1]][d[i]]*p4*p1 + dis[d[i-1]][c[i]]*p3*p2 + dis[d[i-1]][d[i]]*p3*p1);
        //  printf("%.2lf %.2lf %d %d\n",dp[i][j][1],dp[i][j][0],i,j);
        }
    }
    for(int i = 0;i <= m ;i ++){
        ans = min(min(dp[n][i][0],dp[n][i][1]),ans);
    }
    printf("%.2lf",ans);
    return 0;
}

原文地址:https://www.cnblogs.com/wtz2333/p/12233125.html

时间: 2024-11-15 01:18:04

noip部分题目总结的相关文章

[题解+总结]NOIP历年题目分析

1.前言 迎接NOIP的到来...在这段闲暇时间,决定刷刷水题.这里只是作非常简单的一些总结. 2.NOIP2014 <1> 生活大爆炸之石头剪刀布(模拟) 这是一道考你会不会编程的题目...方法有很多,预处理输赢矩阵,或者一大堆if什么的乱搞就行了. <2> 联合权值(搜索) 简单的树上求解问题,由于只需要长度为2的链,只要能够清楚地分析出各种情况,一遍DFS直接出来:自身节点与祖父节点有一对:自身节点与兄弟节点有若干对.在计算权值的时候存在一个优化,即如果每次得到一对之后就计算

NOIP练习赛题目3

魔兽争霸 难度级别:C: 运行时间限制:1000ms: 运行空间限制:262144KB: 代码长度限制:2000000B 试题描述 小x正在销魂地玩魔兽他正控制着死亡骑士和n个食尸鬼(编号1-n)去打猎死亡骑士有个魔法,叫做“死亡缠绕”,可以给食尸鬼补充HP战斗过程中敌人会对食尸鬼实施攻击,食尸鬼的HP会减少,小x希望随时知道自己部队的情况,即HP值第k多的食尸鬼有多少HP,以便决定如何施放魔法.请同学们帮助他:)小x向你发出3种信号:(下划线在输入数据中表现为空格)A_i_a表示敌军向第i个食

NOIP练习赛题目5

小象涂色 难度级别:C: 运行时间限制:1000ms: 运行空间限制:262144KB: 代码长度限制:2000000B 试题描述 小象喜欢为箱子涂色.小象现在有c种颜色,编号为0~c-1:还有n个箱子,编号为1~n,最开始每个箱子的颜色为1.小象涂色时喜欢遵循灵感:它将箱子按编号排成一排,每次涂色时,它随机选择[L,R]这个区间里的一些箱子(不选看做选0个),为之涂上随机一种颜色.若一个颜色为a的箱子被涂上b色,那么这个箱子的颜色会变成(a*b)modc.请问在k次涂色后,所有箱子颜色的编号和

[CODEVS 1043] Noip 2000 方格取数

1043 方格取数 时间限制: 1s  空间限制: 128000 KB 题目描述 Description 设有N*N的方格图(N<=10,我们将其中的某些方格中填入正整数,而其他的方格中则放入数字0.如下图所示(见样例): 某人从图的左上角的A 点出发,可以向下行走,也可以向右走,直到到达右下角的B点.在走过的路上,他可以取走方格中的数(取走后的方格中将变为数字0). 此人从A点到B 点共走两次,试找出2条这样的路径,使得取得的数之和为最大. 输入描述 Input Description 输入的

【NOIP2015】子串

题目描述 有两个仅包含小写英文字母的字符串 A 和 B.现在要从字符串 A 中取出 k 个互不重叠的非空子串,然后把这 k 个子串按照其在字符串 A 中出现的顺序依次连接起来得到一 个新的字符串,请问有多少种方案可以使得这个新串与字符串 B 相等?注意:子串取出 的位置不同也认为是不同的方案. 输入输出格式 输入格式: 输入文件名为 substring.in. 第一行是三个正整数 n,m,k,分别表示字符串 A 的长度,字符串 B 的长度,以及问 题描述中所提到的 k,每两个整数之间用一个空格隔

08day1

高中运动会 最大公约数 [问题描述] 梦幻城市每年为全市高中生兴办一次运动会.为促使各校同学之间的交流,采用特别的分队方式:每一个学校的同学,必须被均匀分散到各队,使得每一队中该校的人数皆相同.为增加比赛的竞争性,希望分成越多队越好.你的任务是由各校的人数决定最多可以分成的队数. [输入] 第一行一个正整数 n ,代表学校的个数. 接下来 n 行,每行一个正整数,分别代表这 n 个学校的人数. [输出] 最多可分成的队数. [数据规模] 对于 100%的数据,n≤500,每个学校人数最多 100

Noip2007提高组总结

两道基础题,后两题比较麻烦,算法想出来后,还是一些细枝末节的问题,需要特别注意,感觉Noip的题目质量还是挺高的,每做一套,都感觉会有大大小小不同的收获,就要月考了,最后把07年的题目总结一下,算是这两天的收获-- T1:统计数字 没有任何悬念的练习题,排序然后输出-- + ? 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 #include <cstdio> #include <algorithm> int n,a[200005],pos; using n

【基础练习】【区间DP】codevs1090 加分二叉树题解

2003 NOIP TG 题目描写叙述 Description 设一个n个节点的二叉树tree的中序遍历为(l,2,3,-,n),当中数字1,2,3,-,n为节点编号.每一个节点都有一个分数(均为正整数),记第j个节点的分数为di,tree及它的每一个子树都有一个加分,任一棵子树subtree(也包括tree本身)的加分计算方法例如以下: subtree的左子树的加分× subtree的右子树的加分+subtree的根的分数 若某个子树为主,规定其加分为1,叶子的加分就是叶节点本身的分数. 不考

HDNOIP2016日记

(这几天感冒没去上学..在家里把电脑搬过来(手虚到摔了2次)写了篇HDNOIP2016日记,大家将就着看吧..) 从2010年开始NOIP的题目都越来越水(为毛一等分数线也越来越低啊喂),本来以为今年能1h水过跑路..看来我还是太年轻.. 周六的考试的前几天连下两场雨,结果我还在磕了药一样的跑2000..不感冒就诡异了QAQ 去考场的路上马拉松正在收场,怡宝的纸杯扔得遍地都是..赞助到一半跑路了? 到了考场门口发现今年ssf霸场..热泪盈眶啊.. 进考场..监考老师标准猥琐大叔..不管了开始写吧