AIM Tech Round 4 (Div. 2)

30 篇文章 0 订阅
5 篇文章 0 订阅

不知不觉,这场已经是很久以前了,一直想补这场,倒不是这场多么特殊,而是d题的随机化,确实是一个比较特殊的算法


A. Diversity

思路:水题,统计字母种类

 

/*
Author Owen_Q
*/

#include <bits/stdc++.h>

using namespace std;

const int maxn = 1010;

char s[maxn];
bool in[maxn];


int main()
{
    int k;
    while(scanf("%s%d",s,&k)!=EOF)
    {
        memset(in,false,sizeof(in));
        int num = 0;
        int len = strlen(s);
        for(int i=0;i<len;i++)
        {
            if(!in[s[i]-'a'])
            {
                in[s[i]-'a'] = true;
                //cout << "*" << s[i] << "*" << endl;
                num++;
            }
        }
        //cout << num <<" "<< k << " "<<len << endl;
        if(k>len)
        {
            printf("impossible\n");
        }
        else if(k<=num)
        {
            printf("0\n");
        }
        else
        {
            printf("%d\n",k-num);
        }
    }
    return 0;
}

 


B. Rectangles

 

思路:简单排列组合,按行列运用乘法原理,最后做个容斥就好了

然而,这题的细节就在于运算符的优先级,按位运算符的优先级相当低,因此对于数字按位操作前,将常数先转成long long才可防溢出

 

/*
Author Owen_Q
*/

#include <bits/stdc++.h>

using namespace std;

const int maxn = 55;

long long row[maxn][2];
long long line[maxn][2];
long long min2[60];

int main()
{
    //cout << (1L<<1L) << " " << (1L<<31L) << " " << (1L<<32L) << " " << (1L<<33L) << endl;
    long long be = 1;
    for(int i=0;i<55;i++)
    {
        min2[i] = be;
        be *= 2L;
        //cout << min2[i] << endl;
    }
    int n,m;
    while(scanf("%d%d",&n,&m)!=EOF)
    {
        memset(row,0,sizeof(row));
        memset(line,0,sizeof(line));
        for(int i=0;i<n;i++)
        {
            for(int j=0;j<m;j++)
            {
                int temp;
                scanf("%d",&temp);
                if(temp==1)
                {
                    row[i][1]++;
                    line[j][1]++;
                }
                else
                {
                    row[i][0]++;
                    line[j][0]++;
                }
            }
        }
        long long sum = -1L * m * n;
        for(int i=0;i<n;i++)
        {
            sum += /*(1L << row[i][0])*/min2[row[i][0]];
            sum --;
            sum += /*(1L << row[i][1])*/min2[row[i][1]];
            sum --;
        }
        for(int j=0;j<m;j++)
        {
            sum += /*(1L << line[j][0])*/min2[line[j][0]];
            sum --;
            sum += /*(1L << line[j][1])*/min2[line[j][1]];
            sum --;
        }
        printf("%I64d\n",sum);
    }
    return 0;
}

 


C. Sorting by Subsequences

 

总结:找规律,数列排序好后寻找最少交换策略,即并查集合并交换元素,即可得到结果

 

/*
Author Owen_Q
*/

#include <bits/stdc++.h>

using namespace std;

const int maxn = 1e5+10;

int pre[maxn];

int finds(int x)
{
    int r = x;
    while(pre[r]!=r)
	{
        r = pre[r];
    }
    int i=x ,j;
    while(pre[i]!=r)
	{
        j = pre[i];
        pre[i] = r;
        i = j;
    }
    return r;
}



void join(int x,int y)
{
    int fx = finds(x);
    int fy = finds(y);
    if(fx > fy)
	{
		int temp = fx;
		fx = fy;
		fy = temp;
	}
    if(fx!=fy)
	{
        pre[fy] = fx;
    }
}

map <int,int> dic;

int a[maxn];
int orda[maxn];
int num[maxn];
vector <int> re[maxn];

int main()
{
    int n;
    while(scanf("%d",&n)!=EOF)
    {
        for(int i=1;i<=n;i++)
        {
            pre[i] = i;
            re[i].clear();
        }
        dic.clear();
        memset(num,0,sizeof(num));
        for(int i=0;i<n;i++)
        {
            scanf("%d",&a[i]);
            orda[i] = a[i];
            dic[a[i]] = i+1;
        }
        sort(orda,orda+n);
        int t = n;
        for(int i=0;i<n;i++)
        {
            if(finds(dic[a[i]]) != finds(dic[orda[i]]))
            {
                join(dic[a[i]],dic[orda[i]]);
                t--;
            }
        }
        for(int i=1;i<=n;i++)
        {
            num[finds(i)]++;
            re[finds(i)].push_back(i);
        }
        printf("%d\n",t);
        for(int i=1;i<=n&&t>0;i++)
        {
            if(num[i]>0)
            {
                t--;
                printf("%d ",num[i]);
                for(int j=0;j<num[i]-1;j++)
                {
                    printf("%d ",re[i][j]);
                }
                printf("%d\n",re[i][num[i]-1]);
            }
        }
    }
    return 0;
}

 

 

 

D. Interactive LowerBound

 

思路:这场比赛的精华之处就在这题了吧

链表查找题,交互,每次可以访问链表的一个元素以及其下一个元素所在位置,2e3步内找出长达5e4的链表内特定元素

由于链表未知,内部结构也未知,因此实在想不到什么O(n)以内的算法,眼看着就会tle,于是随机化大法的神奇之处就出现了

先随机寻找1e3个点,在选择最近的点往后延伸1e3个点,最优可以在2e3的时间内完成1e6的覆盖,这就是随机化的神奇之处了

 

/*
Author Owen_Q
*/

#include <bits/stdc++.h>

using namespace std;

const int maxn = 5e4+10;

typedef struct NODE
{
    int val;
    int nex;
}Node;

vector<int> ran;

bool vis[maxn];
Node askre[maxn];

Node ask(int k)
{
    Node n;
    printf("? %d\n",k);
    fflush(stdout);
    scanf("%d%d",&n.val,&n.nex);
    return n;
}

int main()
{
    int n,start,x;
    srand(time(0));
    /*for(int i=0;i<5;i++)
    {
        if(i%2==0)
        {
            continue;
        }
    }*/
    scanf("%d%d%d",&n,&start,&x);
    ran.clear();
    memset(vis,false,sizeof(vis));
    for(int i=1;i<=n;i++)
    {
        ran.push_back(i);
    }
    random_shuffle(ran.begin(),ran.end());
    vis[start] = true;
    Node p,stp;
    stp = ask(start);
    if(x>(stp.val)&&stp.nex==-1)
    {
        printf("! -1\n");
        fflush(stdout);
    }
    else if(x<stp.val)
    {
        printf("! %d\n",stp.val);
        fflush(stdout);
    }
    else
    {
        vis[start] = true;
        for(int i=0,t=0;t<1000-1&&i<n;i++,t++)
        {
            if(vis[ran[i]])
            {
                t--;
                continue;
            }
            vis[ran[i]] = true;
            p = ask(ran[i]);
            if((p.nex) == -1 && x>(p.val))
            {
                printf("! -1\n");
                fflush(stdout);
                exit(0);
            }
            else if(p.val<=x&&p.val>stp.val)
            {
                stp = p;
            }
        }
        if(stp.val == x)
        {
             printf("! %d\n",stp.val);
             fflush(stdout);
        }
        else
        {
            for(int i=0;i<1000-1;i++)
            {
                if((stp.nex) == -1&&stp.val < x)
                {
                    printf("! -1\n");
                    fflush(stdout);
                    break;
                }
                stp = ask(stp.nex);
                if(stp.val>=x)
                {
                    printf("! %d\n",stp.val);
                    fflush(stdout);
                    break;
                }
            }
        }
    }
    return 0;
}


最后,补充两个知识点

 

(1)fflush(stdout)清空缓存区

(2)random_shuffe(a.begin(),a.end())随机生成一个1~n的全排列,n为数组长度(n = a.end() - a.begin())别忘了播种srand(time(0)),否则生成的仅仅是伪随机数

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值