11.10晚间练习赛 一套全场爆零的好题
nodgd改的题面是真的令人不解
T1 数正方形
题面:
在\(N * N\)的点阵中任取4个点,回答:
问题1:这4个点恰好是“正放”的正方形的4个顶点的方案数是多少?
问题2:这4个点恰好是正方形(包括“正放”和“斜放”)的4个顶点的方案数是多少?
下图为一个4*4的点阵,左图表示一种“正放”的方案,右图表示一种“斜放”的方案。
------
看出来了就是水题
首先你需要在纸上画一画图,把从3~5的方阵中斜放的,且顶点在方阵边界的正方形。
然后你发现,\(N=3\)时有1个;\(N=4\)时有2个;\(N=5\)时三个。
于是规律就出来了。
详情见代码
KONO代码哒!
#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<iostream>
using namespace std;
typedef long long ll;
const ll maxn=100010;
const ll mod=1e9+7;
inline ll po(ll x){return (x*x)%mod;}
ll n,k;
ll pfh[maxn];
inline ll ads(ll x,ll y){return ((x%mod)*(y%mod))%mod;}
int main()
{
// freopen("square.in","r",stdin);
// freopen("square.out","w",stdout);
ll i;
scanf("%lld%lld",&n,&k);
for(i=1;i<=n;i++)
{
pfh[i]=(pfh[i-1]+po(i))%mod;
}
if(k==1)printf("%lld\n",pfh[n-1]);
else{
ll res=0;
for(i=3;i<=n;i++){
res=(res+ads(po(n-i+1),(i-2)))%mod;
}
printf("%lld\n",(pfh[n-1]+res)%mod);
return 0;
}
}
T2 四叶草魔杖同学之间互传答案
题面:
魔杖护法Freda融合了四件武器,于是魔杖顶端缓缓地生出了一棵四叶草,四片叶子幻发着淡淡的七色光。圣剑护法rainbow取出了一个圆盘,圆盘上镶嵌着N颗宝石,编号为0~N-1。第i颗宝石的能量是Ai。如果Ai>0,表示这颗宝石能量过高,需要把Ai的能量传给其它宝石;如果Ai<0,表示这颗宝石的能量过低,需要从其它宝石处获取-Ai的能量。保证∑Ai =0。只有当所有宝石的能量均相同时,把四叶草魔杖插入圆盘中央,才能开启超自然之界的通道。
不过,只有M对宝石之间可以互相传递能量,其中第i对宝石之间无论传递多少能量,都要花费Ti的代价。探险队员们想知道,最少需要花费多少代价才能使所有宝石的能量都相同?
共有\(n\)个同学传递答案,编号为\(0\)~\(n?1\)。为了避免被老师发现,同学们之间传递的答
案都是一次性的,也就是说一份答案如果传到某个同学处被抄了,那其他同学就不能再抄
这份答案了。
这??个同学中,一些是大佬,大佬不需要抄答案,而且可以传出一些答案;还有一些
是蒟蒻,答案传到蒟蒻手上时,蒟蒻会根据自己的需求抄一些答案,并将剩余的答案传给
其他人。准确的说,第i个同学有一个数值\(A_i\),\(A_i>0\)表示这位同学是大佬,他会传出Ai份
答案;\(A_i<0\)表示这位同学是蒟蒻,他需要抄?\(A_i\)份答案。而且,答案的供需关系是平衡
的,即\(A0+A1+?+An?1=0\)。
然而,机房传答案收到很多限制,所以只有m对同学之间可以相互传答案。一对同学
之间传递答案是有代价的:如果整个过程中都不传答案,则代价为 0;如果传了答案,无
传多少份答案,无论传答案是哪个方向,代价都是固定的。
现在,请你计算最少需要多大代价,才能保证答案的正常流通?
\(2<=N<=16,0<=M<=N*(N-1)/2,0<=pi,qi<N,-1000<=Ai<=1000,0<=Ti<=1000,∑Ai=0\)。
考试时:
WZJ&Wx2004:会不会是最小生成树?
WZJ:把所有区块和=0的块连起来?
WZJ:不对,区块可能很多,要炸。
讲题时:
WZJ:WDNMD
题解:
最小生成树+状态压缩
一想到每个点值和为0的区块不需要连上其他点值和为0的区块,我们就想到了分成区块来处理。一看到\(n\)不大于16,状态压缩没跑了。
首先设全集为tot,则把tot内所有区块点值的和为0的情况找出来,每个跑一次最小生成树
。把其余不为0的子集dp值设为inf。
然后再枚举tot子集,用\(3^N\)的暴力算法转移。
转移方程为:\(Dp[s]=min \{ Dp[s],Dp[s']+Dp[s\)^$ s‘] }\((其中\)s‘\(为\)s$子集)。
爆不了。
注:在跑最小生成树时要注意判断能否各点之间能否到达,若不能则把该集合的值设为inf
inf要开大。
KONO代码哒!
#include<cstdio>
#include<iostream>
#include<cmath>
#include<cstring>
#include<algorithm>
using namespace std;
//不要用不要用不要用链式!
char *p1,*p2,buf[1<<20];
// #define GC (p1==p2&&(p1=buf,p2=buf+fread(buf,1,1<<20,stdin),p2==p2)?0:(*(p1++)))
#define GC getchar()
inline int in()
{
int w=0,x=0;
char ch=0;
while(!isdigit(ch)){
w|=ch=='-';
ch=GC;
}
while(isdigit(ch))
{
x=(x<<3)+(x<<1)+(ch^48);
ch=GC;
}
return w? -x:x;
}
const int maxn=20;
const int maxm=1000;
const int inf=0x3f3f3f3f;
struct edge{
int from,to,len;
}g[maxm];
bool cmp(edge a,edge b)
{
return a.len<b.len;
}
int cnt;
int n,m;
int a[maxn];
int Val[1<<maxn];
int f[1<<maxn];
int dp[1<<maxn];
int fa[maxn];
void add(int from,int to,int len)
{
g[++cnt].from=from;
g[cnt].len=len;
g[cnt].to=to;
}
bool x1[maxn];
int gf(int x)
{
if(fa[x]!=x)fa[x]=gf(fa[x]);
return fa[x];
}
void mst(int num)
{
int i,j;
int cnt1=0;
for(i=0;i<n;i++)fa[i]=i,x1[i]=0;
int tmp=num,c1=0;
while(tmp){
if(tmp&1)x1[c1]=1,++cnt1;
++c1;
tmp=(tmp>>1);
}
int res=0,k=0;
for(i=1;i<=m&&k<cnt1-1;i++){
int u=g[i].from,v=g[i].to;
if(!x1[u]||!x1[v])continue;
int fx=gf(u),fy=gf(v);
if(fx==fy)continue;
fa[fy]=fx;
res+=g[i].len;
k+=1;
}
if(k!=cnt1-1){
f[num]=inf;
}
else f[num]=res;
}
int main()
{
memset(f,0x3f,sizeof(f));
memset(dp,0x3f,sizeof(dp));
n=in();m=in();
int i,j;
for(i=0;i<n;i++)a[i]=in();
for(i=1;i<=m;i++){
int x=in(),y=in(),z=in();
add(x,y,z);
}
int tot=(1<<n)-1;
for(i=1;i<=tot;i++)
{
int u=i,c=0;
while(u){
if(u&1)Val[i]+=a[c];
u=(u>>1);
c+=1;
}
}
sort(g+1,g+m+1,cmp);
for(i=1;i<=tot;i++)
{
if(Val[i]==0){
mst(i);
}
}
for(i=1;i<=tot;i++){
dp[i]=f[i];
for (int j = i; j; j = (j - 1) &i){
dp[i]=min(dp[i],dp[j]+dp[i^j]);
}
}
if(dp[tot]!=inf)
printf("%d\n",dp[tot]);
else printf("Impossible\n");
}
注意有10分的\(Impossible\)点。
T3 金轮法王的龙象般若功却被老师逮个正着
啥玩意儿?!
题面:
同学们在教室里传答案被逮到了,但问题不大,以前被逮到过很多次了。
全班共有个\(N\)同学, 每次参与传答案的同学都是个同学的一个非空子集。 一学期共有
\(2^N\)次考试,每次考试参与传答案的同学都不完全相同。
老师每次考试有一半的概率记录这次考试参与传答案的同学名单,也有一半的概率当
做什么也没发生。到了期末,老师检查一下自己记下的名单,找出每次都参与了传答案的
同学,作为这学期的“始作俑者”。特别的,如果老师一学期没有记录任何一次考试的传答
案名单,则没有学生是“始作俑者”。
老师对第\(i\)个学生的惩罚系数是正整数\(A_i\)。期末抓出始作俑者之后,算出始作俑者人数
\(x\)和最大的惩罚系数\(y\),对全班施加的惩罚量\(z=xy\)特别的,如果没有学生是始作俑者,
惩罚量为0。
求期末惩罚量的期望\(E(z)\),输出\(E(z)*{2^2}^n\%998244353\)。可以证明\(E(z)*{2^2}^n\)为整数。
\(N\leq2^{12}\),\(|A_i|\leq2^{20}\)
我没有什么好讲的。详见wangdy带佬的题解。
总结:
- 组合算法就组合算法嘛,打就是了嘛,不要怕嘛
- 多想一点算法嘛。不要看着什么就是什么嘛
- 不要放掉期望的题,就算不你会做也要骗点分再走嘛
?
?
OIer眼中的图片
原文地址:https://www.cnblogs.com/cooper233/p/11833866.html