limn2o4个人训练实录

一些比较好的题会单独写个题解

1.2015 ACM/ICPC Asia Regional Shenyang Online

这场有点难啊,什么矩阵循环群也是第一次听说,这次solo再次暴露出了我数学推导的弱的问题……
进度【3/13】
HDU 5455 Fang Fang
这道题就是纯模拟,但是注意要判断有没有多余的字符……

HDU 5461 Largest Point
这道题是简单贪心,维护两个 vector,分别存 at1^2 和 bt2,然后就选两个最大值,如果最大值就都是一个数就取次大值比较一下。

HDU 5459 Jesus Is Here
大概想了一下,首先我们知道答案dp[i] = dp[i-1] + dp[i-2] + 一堆新生成的数,我们分别维护计算出这个数的其他值就可以了,其他的值是可以递推求的:
len[i] 第i个串的长度,明显的斐波那契
cnt[i] 第i个串里面有几个c ,明显的斐波那契
dist[i] 第i个串里面所有c到串结尾的距离的和,dist[i] = dist[i-1] + dist[i -2] + cnt[i-2]len[i-2],相当于i-2串的每个c都要往后续len[i-1]的长度
所以最后相当于是先把i-1串到i-2串的距离加上 : cnt[i-1] * dist[i-2],然后就是用上面的式子推一下:cnt[i-1] * dist[i-2]+ cnt[i-2]
(len[i-1]* cnt[i-1] - dist[i-1])
记得疯狂取模就行了

2. 2015 ACM/ICPC Asia Regional Shanghai Online

进度[3/11] 似乎被3诅咒了……
HDU 5477 A Sweet Journey
我直接写了个二分,但是感觉是直接顺着扫一遍就行了。
二分最后的答案,判断能不能走过去,注意区间和点的转换
HDU 5475 An easy problem
看起来是easy的problem……一开始直接写了个java大数上去,没想到线段树1A了
首先我们把数组初始化成1(不能用memset),对于乘的操作,就直接在对应查询的位置上添加这个数,除法就是把对应位置上的数变成1,用通过线段树维护一个区间积+取模。
HDU 5478 Can you find it
日常不会推式子系列……
我们先把原来的式子放到这里 a k 1 ⋅ n + b 1 + b k 2 ⋅ n − k 2 + 1 = 0 ( m o d C ) a^{k1 \cdot n+b1} + b^{k2 \cdot n - k2 +1} = 0 (mod C) ak1n+b1+bk2nk2+1=0(modC)
观察右边,似乎当n等于1的时候: a k 1 + b 1 + b = 0 ( m o d C ) a^{k1+b1} + b = 0 (mod C) ak1+b1+b=0(modC)
n等于2的时候 a k 1 ⋅ 2 + b 1 + b k 2 + 1 = 0 ( m o d C ) a^{k1 \cdot 2+b1} + b^{k2 +1} = 0 (mod C) ak12+b1+bk2+1=0(modC)
然后我们只要顺着遍历一下a,通过n等于1的式子反算出b,然后带入n等于2的式子验证一下。
至于证明可以简单灯上式进行合并,相信聪明的读者不难证明

3. 2018 USP-ICMC

之前还做了一场,但是制作了水题,这次稍微好一点
I I will go
把这个翻译成“我一定来”,先对关系求出dfs序,注意要取相反的关系进行判断,要仔细读题呀。
然后发现剩下就是三道水题,难受

4.Asia-Tsukuba 2017

A Aizu 1378 Secret of Chocolate Poles
我读题的时候一直在考虑?这是签到题吗?
就是走楼梯走两遍就可以了
B - Parallel Lines
吐血暴力dfs,枚举一个点,把所有和这个点相连的向量存起来,最后对得到的向量判断一次。

#include <bits/stdc++.h>
#define ll long long
#define pr pair<int,int>
#define mp make_pair
#define pb push_back
#define fi first
#define se second
#define next fuck
using namespace std;
struct Pt
{
    int x,y;
    Pt(){};
    Pt(int _x,int _y){x = _x,y = _y;}
    Pt operator - (const Pt &b) const
    {
        return Pt(x-b.x,y-b.y);
    }
    int operator ^ (const Pt &b) const
    {
        return x*b.y - y*b.x;
    }
}p[30],vec[1001];
bool used[30];
bool _check(int a,int b,int c,int d)
{
    return ((p[a]-p[b])^(p[c]-p[d])) == 0;
}
int n,tot,ans;
void dfs(int pos)
{
    while(pos <= n && used[pos]) pos++;
    if(pos == n+1)
    {
        int temp = 0;
        for(int i = 0;i<tot;i++)
        {
            for(int j =i+1;j<tot;j++)
            {
                if(vec[i].x * vec[j].y == vec[i].y*vec[j].x) temp++;
            }
        }
        ans = max(ans,temp);
    }
    used[pos] = 1;
    for(int i = 1;i<=n;i++)
    {
        if(!used[i])
        {
            used[i] = 1;
            vec[tot++] = Pt(p[i].x - p[pos].x,p[i].y - p[pos].y);
            dfs(pos+1);
            tot--;
            used[i] = 0;
        }
    }
    used[pos] = 0;
}
int main()
{
    cin>>n;
    for(int i = 1;i<=n;i++)
    {
        cin>>p[i].x>>p[i].y;
    }
   //cout<<_check(1,4,2,3)<<endl;
    ans = 0;
    tot = 0;
    dfs(1);
    cout<<ans<<endl;
    return 0;
}

C - Medical Checkup
读题20分钟,AC5分钟系列
题意是一群人去体检,每个人的在每个项目上的时间是一样的。排队顺序不能改变,并且检查的项目也不能该表,然后求出t时间的时候,每个人正在排队的项目
我们先来分析一下,由于不能太提前去排别的项目,每个人在前往第一个点的时候一定等了前缀和的时间,那么对于第一个人,他的值直接算一下就可以了。当然对于后面的人,如果时间小于他等待第一个项目的时间,就直接输出1.
我们接着分析,减去前缀和时间之后,这个人在每个项目的等待时间,就之和前面的最长的时间有关系,相当于这个人不走,我们就得等着。

#include <bits/stdc++.h>
#define ll long long
#define pr pair<int,int>
#define mp make_pair
#define pb push_back
#define fi first
#define se second
#define next fuck
using namespace std;
const int MAXN = 1e5 + 5;
ll h[MAXN];
ll sum[MAXN];
int main()
{
    int n,t;
    scanf("%d%d",&n,&t);
    for(int i = 1;i<=n;i++)
    {
        scanf("%lld",&h[i]);
        sum[i] = sum[i-1] + h[i];
    }
    ll mx = h[1];
    printf("%lld\n",t/mx+1);
    for(int i = 2;i<=n;i++)
    {
        mx = max(mx,h[i]);
        if(sum[i] > t) printf("1\n");
        else printf("%lld\n",(t-sum[i])/mx+2);  //算到第一个项目的时候+1,到现在的项目+1
    }
    return 0;
}

E - Starting a Scenic Railroad Service
又是阅读理解题,其实就两个问题:
1.一个区间和其他区间的交集最多个数
2.一个点的最多重叠区间个数
问题2明显就是个差分,那我们来解决问题一,我们记录一个左右端点的前缀数组,然后答案就是右端点前面的左端点个数-减去左端点前面的右端点个数。相当于是本区间结束之前开始的节点,减去已经结束的点,就是两个节点都落在本区间的区间个数。

#include <bits/stdc++.h>
#define ll long long
#define pr pair<int,int>
#define mp make_pair
#define pb push_back
#define fi first
#define se second
#define next fuck
using namespace std;
const int MAXN = 2e5 + 5;
const int N = 100000;
int cnt[MAXN],a[MAXN],b[MAXN],l[MAXN],r[MAXN];
int main()
{

    int n;
    scanf("%d",&n);
    for(int i = 1;i<=n;i++)
    {
        scanf("%d%d",&a[i],&b[i]);
        cnt[a[i]]++,cnt[b[i]]--;
        l[a[i]]++,r[b[i]]++;
    }
    int ans1 = 0,ans2 = 0;
    for(int i  =1;i<=N;i++)
    {
        cnt[i] += cnt[i-1];
        l[i] += l[i-1];
        r[i] += r[i-1];
        ans2 = max(ans2,cnt[i]);
    }
    for(int i  =1;i<=n;i++)
    {
        ans1 = max(ans1,l[b[i]-1] - r[a[i]]);
    }
    printf("%d %d\n",ans1,ans2);
    return 0;
}

我再也不做JP赛区的题了……

5.2016-2017 ACM-ICPC, Asia Tsukuba Regional Contest

真香……
A
Rearranging a Sequence
我的做法是按照出现在操作序列的顺序排序,出现的时间越靠后的数字越靠前,其他没有在操作序列的数就按照从小到大排。
B
Quality of Check Digits
吐血大模拟,将一个矩阵恢复之后再第二个矩阵上跑一下就行。
我写第一个矩阵的方法是每次能斜着走就斜着走(每次要换方向),不能斜着走就判断在那个边上(注意优先级),现在边上走一步,然后再斜着走一步。
C
Distribution Center
题意比较简略,用了很长的时间才反应过来……
做法是将机器臂按照x坐标排序,然后对于排过序的机器臂,更新出来每个传送带最早能接受的编号和最后能接受的编号。因为机器臂连接之后的之前连接的传送带也被添加进来了,相当两个区间合并,只要用这样的方法更新端点值就可以了。
D Hidden Anagrams
问A串中最长的且打乱顺序是B串的字串的最长字串。
打乱顺序之后,并没有改变一个字串的构成,只要两个字串的构成一样就可以认为是符合要求的。我们统计每个字串中每个字符出现的个数,然后将这个cnt数组当成一个字符串hash一下。
注意不能n^3无脑枚举,要采用枚举长度然后滑动的方法来更新。

2014-2015 ACM-ICPC, Asia Tokyo Regional Contest

又是JP题……
A Bit String Reordering
小模拟,根据长度信息恢复出两个序列,暴力向后找一个一样的数交换过来,就是最优的。
证明的话可以反证一下
B Miscalculation
中模拟,按照两个计算顺序来判断和给出的结果之间的关系。
我处理乘法优先的时候,首先把乘法的结果放在右边的数字位置上,左边的数变成0,之后再做一次加法。
C Shopping
贪心一下,首先更新每个点最远需要去的地方,然后对于这样形成的区间[l,r],我们不断用这个区间里面的左端点l,更新最远需要走到的r,相当于我们要在更新过后的区间走个来回,这样一定是最优的。
F There is No Alternative
翻译一下标题:这没得选!
输出最小生成树上有多少天不能替代的边,并输出这个总和。
由于点数很少,我们先来一发mst,并记录mst上的边。之后我们暴力删除每个边,判断新的mst的值会不会变化。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值