HDU2018多校第二场部分题目

HDU2018多校第二场部分题目

这场打崩了啊,全世界都过的EF全都没出来啊,然后就过了4题啊。。。

C Cover(hdu 6311)

题目描述
http://acm.hdu.edu.cn/showproblem.php?pid=6311

题解
给你一张图求最少需要多少条路径能够覆盖所有边。
把原图中所有的奇度点两两配对连边跑一遍欧拉回路,然后再把新加的边删掉就好了。

代码

#include<bits/stdc++.h>
#define N 200010
#define M 400010
using namespace std;
int n,m,res,d[N],tot,cnt,ans[N],po[N],flag[N];
int k,la[N],ff[M],now[N],used[M];
vector<int>t[N];
struct node{int a,b;}e[M];
void add(int a,int b)
{
  e[++k]=(node){a,b};ff[k]=la[a];la[a]=k;now[a]=la[a];
  e[++k]=(node){b,a};ff[k]=la[b];la[b]=k;now[b]=la[b];
}

int get(int e){
  return (e&1)?-(e>>1):(e>>1);
}

void dfs(int x)
{
  for(;now[x];now[x]=ff[now[x]])
  {
    int a=now[x];
    if(used[a])continue;
    used[a]=1;used[a^1]=1;
    dfs(e[a].b);ans[++cnt]=get(a);
  }
}

void find(int x)
{
  flag[x]=1;po[++tot]=x;
  for(int a=la[x];a;a=ff[a])
    if(!flag[e[a].b])find(e[a].b);
}

int main()
{
  //freopen("1.txt","r",stdin);
  //freopen("2.txt","w",stdout);
  int a,b;
  while(~scanf("%d%d",&n,&m))
  {
    memset(la,0,sizeof(la));
    memset(ff,0,sizeof(ff));
    memset(d,0,sizeof(d));k=1;res=0;
    memset(used,0,sizeof(used));
    memset(po,0,sizeof(po));
    memset(now,0,sizeof(now));
    memset(flag,0,sizeof(flag));
    for(int i=1;i<=m;i++)
      scanf("%d%d",&a,&b),add(a,b),d[a]++,d[b]++;
    for(int i=1;i<=n;i++)
    {
      if(flag[i])continue;
      tot=0;find(i);
      int pre=0,pos=0;
      for(int j=1;j<=tot;j++)
        if(d[po[j]]&1)
        {
          pos=po[j];
          if(pre)add(pre,po[j]),pre=0;
          else pre=po[j];
        }
      cnt=0;
      if(!pos)dfs(po[1]);
      else dfs(pos);
      if(!cnt)continue;
      for(int j=cnt;j;j--)
      {
        if(abs(ans[j])>m)continue;
        if(abs(ans[j+1])>m||j==cnt)res++;
        t[res].push_back(ans[j]);
      }
    }
    printf("%d\n",res);
    for(int i=1;i<=res;i++){
      printf("%d",t[i].size());
      for(int j=0;j<t[i].size();j++)printf(" %d",t[i][j]);
      printf("\n");
    }
    for(int i=1;i<=res;i++)t[i].clear();
  }
  return 0;
}

E Hack It(hdu 6313)

题目描述
http://acm.hdu.edu.cn/showproblem.php?pid=6313

题解
构造一个n*n的矩形,使得不存在四个角都是1的矩形,并要求至少有85000个1。
2000*sqrt(2000)大概就是85000,疯狂暗示???
把矩形分成sqrt(n)*sqrt(n)份,每份每行放一个1。
第一行的矩阵随便构造,然后往下的话每一行等于上一行右移一位。
sqrt(n)取个质数避免冲突,选了47。

代码

#include<bits/stdc++.h>
#define N 2500
using namespace std;
int n=2000,m=47,s[N][N];
int main()
{
  for(int i=0;i<m;i++)
    for(int j=0;j<m;j++)
      for(int k=0;k<m;k++)
        s[m*i+j][m*k+(j*k+i)%m]=1;
  printf("%d\n",n);
  for(int i=0;i<n;i++){
    for(int j=0;j<n;j++)printf("%d",s[i][j]);
    printf("\n");
  }
  return 0;
}

F Matrix(hdu 6314)

题目描述
http://acm.hdu.edu.cn/showproblem.php?pid=6314

题解
显然行和列独立考虑,最后乘起来就好了。
题目要求至少A行,我们枚举恰好i行,方案数为 C(n,i)某神秘容斥系数f[i]剩下随便放。
容斥系数不会推啊,就凉了啊。
容斥系数 f[i]=1-ΣC(i,j)*f[j],即对于比i小的每个j,会被算C(i,j)次,再乘个对应的容斥系数。

代码

#include<bits/stdc++.h>
#define ll long long
#define mod 998244353
#define N 3005
using namespace std;
int n,m,A,B;ll ans,p[N*N],f[N],g[N],res,C[N][N];
const int maxn=3000;
int main()
{
  p[0]=1;C[0][0]=1;
  for(int i=1;i<=maxn*maxn;i++)p[i]=p[i-1]*2%mod;
  for(int i=1;i<=maxn;i++)
  {
    C[i][0]=1;
    for(int j=1;j<=maxn;j++)
    {
      C[i][j]=C[i-1][j-1]+C[i-1][j];
      if(C[i][j]>=mod)C[i][j]-=mod;
    }
  }
  while(~scanf("%d%d%d%d",&n,&m,&A,&B))
  {
    ans=0; 
    for(int i=A;i<=n;i++)
    {
      res=0;
      for(int j=A;j<i;j++)res=(res+C[i][j]*f[j])%mod;
      f[i]=1-res+mod;if(g[i]>=mod)f[i]-=mod;
    }
    for(int i=B;i<=m;i++)
    {
      res=0;
      for(int j=B;j<i;j++)res=(res+C[i][j]*g[j])%mod;
      g[i]=1-res+mod;if(g[i]>=mod)g[i]-=mod;
    }
    for(int i=A;i<=n;i++)
      for(int j=B;j<=m;j++)
        ans=(ans+f[i]*C[n][i]%mod*g[j]%mod*C[m][j]%mod*p[(n-i)*(m-j)])%mod;
    printf("%d\n",ans);
  }
  return 0;
} 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值