Codeforces Round #332 (Div. 2)

【A. Patrick and Shopping】
【题目大意】有三个点,给出两点之间的距离,求从A出发访问BC后返回A的最短路径。

【分析】乱搞即可……对于我这种蒟蒻写出所有的情况最粗暴,第一次还没考虑全……
代码:

#include <cstdio>
#include <algorithm>
using namespace std;

int main()
{
    int d1,d2,d3;
    scanf("%d%d%d",&d1,&d2,&d3);
    int ans1=d1+d1+d2+d2;
    int ans2=d1+d2+d3;
    int ans3=d1+d1+d3+d3;
    int ans4=d2+d2+d3+d3;
    printf("%d\n",min(min(ans1,ans2),min(ans3,ans4)));
}

【B. Spongebob and Joke】
【题目大意】输入数列f与数列a,求数列a(i)使得b(i) = f(a(i)),若不存在输出Impossible,若多解输出Ambiguity。

【分析】开个Map模拟一下好了……神TM最后一分钟给人叉了,神TM最后两秒改对交了……虽然没卵用还是没多少分……
代码:

#include <cstdio>
#include <algorithm>
#include <map>
using namespace std;

map<int,int> mm;
int a[100100],b[100100],f[100100],cnt[100100];

int main()
{
    int n,m,Ambiguity=0;
    scanf("%d%d",&n,&m);
    for (int i=1; i<=n; i++) { scanf("%d",&f[i]); mm[f[i]]=i; cnt[f[i]]++; }
    for (int i=1; i<=m; i++) scanf("%d",&b[i]);

    for (int i=1; i<=m; i++)
    {
        if(mm.find(b[i])==mm.end()) { puts("Impossible"); return 0; }
        int x=mm[b[i]];
        if (cnt[b[i]]>1) Ambiguity=1;
        a[i]=x;
    }
    if (Ambiguity) { puts("Ambiguity"); return 0; }
    puts("Possible");
    for (int i=1; i<=m; i++) printf("%d ",a[i]);
}

【C. Day at the Beach】
【题目大意】有一列数,分成若干块分别排序,求最多能分成多少块,使得排序后整个数列有序。

【分析】模拟一下,从最小的数到最大的数依次考虑,当前块必须把当前最小的数包含进去,可以分块就分。
代码:

#include <cstdio>
#include <algorithm>
using namespace std;

struct node { int v,id,tag; } a[100010];
int cmp1(node x, node y) { return x.v<y.v; }
int cmp2(node x, node y) { return x.id<y.id; }

int ccount[100010];

int main()
{
    int n,tt;
    scanf("%d",&n);
    for (int i=1; i<=n; i++) scanf("%d",&a[i].v),a[i].id=i;
    sort(a+1,a+n+1,cmp1);
    a[1].tag=tt=1; ccount[tt]=1;
    for (int i=2; i<=n; i++)
    {
        if (a[i].v!=a[i-1].v) tt++;
        a[i].tag=tt; ccount[tt]++;
    } 
    sort(a+1,a+n+1,cmp2);

    int nowh=1,maxh=0,block=0;

    for (int i=1; i<=n; i++)
    {
        ccount[a[i].tag]--;
        maxh=max(maxh,a[i].tag);
        while (!ccount[nowh]) nowh++;
        if (nowh>=maxh) block++; 
    }
    printf("%d\n",block);
}

【D. Spongebob and Squares】
【题目大意】给定一个整数k,求所有子正方形个数和为k的矩形,升序输出长和宽。

【分析】推公式,然后枚举长或者宽,使用set统计……我刚开始脑抽用vector。结果k=1输出了2 1 1 1 1
代码:

//n列m行网格(m<=n)子正方形个数——(3*n-m+1)*(m*(m+1))/6 

#include <cstdio>
#include <algorithm>
#include <set>
using namespace std;

set<pair<long long,long long> > s;
set<pair<long long,long long> >::iterator it;

int main()
{
    long long xx;
    scanf("%I64d",&xx); xx*=6;
    long long m=0;
    while (++m<2000000)
    {
        long long x=xx;
        if (x%m || x%(m+1)) continue;
        x/=m,x/=m+1; x+=m-1;
        if (x%3) continue;
        long long n=x/3;
        if (n<m) break; 
        s.insert(make_pair(m,n));
        s.insert(make_pair(n,m));
    }

    printf("%d\n",s.size());
    for(it=s.begin(); it!=s.end(); it++)
        printf("%I64d %I64d\n",it->first,it->second);
} 

【D. Spongebob and Squares】
【题目大意】有一个以1为根的树,给出m条树上的边及q组LCA关系(a,b,c)即c为a和b的祖先,求符合条件的树的数量。

【分析】神TM状压DP……我太水了于是乎写了记忆化,打比赛时连题目都没看懂……
代码:

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
#define mk make_pair
using namespace std;
typedef long long LL;

int n,m,q;

vector<pair<int,int> > lca[14];
int c[14][14],mark[14],obey[14][1<<13];
LL f[14][14][14][1<<13];

LL calc(int fa,int u,int v,int cv)
{

    if(f[fa][u][v][cv]!=-1) return f[fa][u][v][cv];
    if (v==n) 
    {
        f[fa][u][v][cv]=(cv==0);
        return f[fa][u][v][cv];
    }
    if(v==u || (cv&1<<v)==0)
    {
        if(c[u][v]&&(v!=fa))return 0;
        f[fa][u][v][cv]=calc(fa,u,v+1,cv);
        return f[fa][u][v][cv];
    }
    LL ret=0;
    for (int m=cv; m>0; m--)
    {
        m&=cv;
        if(obey[u][m] && ((mark[v]|m)==m))
            ret+=calc(u,v,0,m-(1<<v))*calc(fa,u,v+1,cv-m);
    }
    if (!(c[u][v] && (v!=fa))) ret+=calc(fa,u,v+1,cv);
    f[fa][u][v][cv]=ret;
    return ret;
}

int main()
{
    scanf("%d%d%d",&n,&m,&q);

    int x,y,z;
    for (int i=0;i<m;i++)
    {
        scanf("%d%d",&x,&y); x--;y--;
        c[x][y] = c[y][x] = true;
    } 
    for (int i=0; i<q; i++)
    {
        scanf("%d%d%d",&x,&y,&z); x--;y--;z--;
        lca[z].push_back(mk(x,y));
    }

    for (int i=0;i<n;i++)
    {
        mark[i] = 1<<i;
        for (int j=0; j<lca[i].size(); j++) 
        {
            pair<int,int> x=lca[i][j];
            mark[i]|=1<<x.first|1<<x.second;
        }

        for (int s=(1<<n)-1; s>0; s--)
            if (!(s&1<<i))
            {
                obey[i][s]=1;
                for (int j=0; j<lca[i].size(); j++)
                {
                    pair<int,int> x=lca[i][j];
                    if ((s&1<<x.first) && (s&1<<x.second)) { obey[i][s]=0; break; }
                }
            }
    } 
    memset(f,-1,sizeof f);
    LL ans=calc(0,0,0,(1<<n)-2);
    printf("%I64d\n",ans);
} 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值