Asia Yokohama Regional Contest 2018 ABCG

第三周多校一题三小时滚蛋去吃KFC

太惨了 起手我看的第一个就是这场区域赛过的最少的H四色定理 然后右下角看了将近10min 倒是想到了拓扑排序 不过右下角的度一定小于等于4的性质没看出来 也根本不会写拓扑排序

然后第二个看的就是F计算几何 倒是可以一眼看出最长的线就是旋转卡壳的思想 但是最短的线看完题解还是觉得有点神奇。。

现场一小时才出A还wa了一发 回来自己再做又在一个小地方考虑不完善调了一个小时

 

A:字符串比大小 主串和n个字符串比较 小于输出-大于等于输出+ 遇到数字则比数字大小

如果一定要说难点就是在两个数字比较完之后的操作要考虑完善每一种可能性 不要漏情况 比如以下就是一个考虑不完善的代码

#include 

using namespace std;

int main()
{
//    cout<>n)
    {
        cin>>s1;
        l1=s1.size();
        while(n--)
        {
            cin>>s2;
            l2=s2.size();
            k1=0,k2=0;
            flag=false;
            while(k1l2)
                            {
                                ans=true;
                            }
                        }
                        else
                        {
                            continue;
                        }
                    }
                    else
                    {
                        ans=(ret2

B:从n个数字选出最长的等差序列

现场和聚聚一直在调n^2logn 甚至没有得到一发tle。。

应该要是dp 利用等差序列a[i-1]+a[i+1]==2*a[i]的性质进行求解

所以任何dp[i][j]=2(i

注意一下转移的时候注释内外的区别 当我们发现i、j、k可以组成等差序列的时候,我们要做的应该是利用i、j的已有的状态来更新j、k。而不是每次只更新i、k,这样只是孤立地看待每三个元素之间的关系,所以无论最终的长度是多少,最长也只会是3

#include 

using namespace std;
const int N=5050;
int a[N],dp[N][N];
int main()
{
    int n,ans;
    while(cin>>n)
    {
        ans=2;
        for(int i=0;i>a[i];
        }
        sort(a,a+n);
        for(int i=0;i=0&&k

C:大巴车上两遍坐人 排队下车 每一秒所有能动的人动一下 问最少的时间

考虑相反问题 下车需要考虑排队等待 上车就不需要了 所以按距离排序 最长时间的最先走即可

现场其实一眼就看出来了 然后队友说没听懂 要我证明 然后又想不到相反的问题 于是就凉了

#include 

using namespace std;
vectorv;
int main()
{
    int r,s,p,x,y,ans;
    while(cin>>r>>s>>p)
    {
        v.clear();
        for(int i=0;i>x>>y;
            x=r-x+1;
            if(y>s)
            {
                y-=s;
            }
            else
            {
                y=s-y+1;
            }
            v.push_back(x+y);
        }
        sort(v.begin(),v.end());
        ans=0;
        for(int i=0;i

G:问最少交换多少次使得序列先递增后递减

现场没看 回来一直在调枚举每个位置 使得该位置左边递增右边递减的做法 然后因为很久没写树状数组了 很久之后才发现这个位置不一定会是递增序列和递减序列的合法分界点 于是看题解 从小到大将数放到最旁边去即可 不需要计算逆序对更不需要计算如果要组成单调序列所需要的操作数量

看了题解之后还有很多细节没有考虑到,比如题解提醒过的多个相同数字的处理,以及处理过程中的一些操作。

#include 
#define ll long long
/**
    前面的递增和后面的递减的连接点不同的问题还没有解决。
    这个问题的实质其实是将某个位置前面的所有数字重新排序,
    再把后面的数字重新排序是不是一定能组成满足题意的解。
    其实不然。
*/
using namespace std;
map< ll,pair >mp;
const ll N=1e6+10;
ll a[N],c[N],num[N];
ll lowbit(ll x){return x&-x;}
void update(ll x,ll y)
{
    while(x<=N)
    {
        c[x]+=y;
        x+=lowbit(x);
    }
}
ll sum(ll x)
{
    ll ret=0;
    while(x)
    {
        ret+=c[x];
        x-=lowbit(x);
    }
    return ret;
}
struct Node{
    ll pos;
    ll value;
    bool operator<(const Node&b)const{
        if(value==b.value){
            return pos>n)
    {
        memset(c,0,sizeof(c));
        memset(num,0,sizeof(num));
        mp.clear();
        ans=0;
        for(ll i=1;i<=n;i++)
        {
            cin>>a[i];
            num[a[i]]++;
            b[i]=Node{i,a[i]};
            update(i,1);
        }
        sort(b+1,b+1+n);
        ll last=1;
        b[n+1]=Node{n+1,-1};
        for(ll i=1;i<=n+1;i++)
        {
            if(b[last].value!=b[i].value)
            {
                mp[b[last].value]=make_pair(last,i-1);
                last=i;
            }
        }
        for(ll k=1;k<=n;k++)
        {
//            cout<<"i="<y)
            {
                update(b[j].pos,-1);
                ans+=y;
                mp[b[j].value].second--;
            }
            else
            {
                update(b[i].pos,-1);
                ans+=x;
                mp[b[i].value].first++;
            }
        }
        cout<

之后和同学交流的时候又看了同学精妙的代码,就是算逆序对,不过不是来算单调序列的步数,而是计算两边比这个数大的数的数量。如下。

#include 
using namespace std;
typedef long long ll;
const int N=100000;
int a[200005],n,b[200005],l[200005],r[200005];
ll ans;
inline int lb(int x){
    return x&(-x);
}
void add(int x,int k){
    for(int i=x;i<=N;i+=lb(i))
        b[i]+=k;
}
int sum(int x){
    int ans=0;
    for(int i=x;i;i-=lb(i)){
        ans+=b[i];
    }
    return ans;
}
int main(){
    scanf("%d",&n);
    for(int i=1;i<=n;i++){
        scanf("%d",&a[i]);
        add(a[i],1);
        l[i]=sum(N)-sum(a[i]);
    }
    memset(b,0,sizeof(b));
    for(int i=n;i>=1;i--){
        add(a[i],1);
        r[i]=sum(N)-sum(a[i]);
    }
    for(int i=1;i<=n;i++){
       // cout<

 

你可能感兴趣的:(思维)