这场打崩了啊,全世界都过的EF全都没出来啊,然后就过了4题啊。。。
题目描述
http://acm.hdu.edu.cn/showproblem.php?pid=6311
题解
给你一张图求最少需要多少条路径能够覆盖所有边。
把原图中所有的奇度点两两配对连边跑一遍欧拉回路,然后再把新加的边删掉就好了。
代码
#include
#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;jprintf(" %d",t[i][j]);
printf("\n");
}
for(int i=1;i<=res;i++)t[i].clear();
}
return 0;
}
题目描述
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
#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;ifor(int j=0;jprintf("%d",s[i][j]);
printf("\n");
}
return 0;
}
题目描述
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
#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
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
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;
}