noip模拟28[我要玩符卡|我有超能力]
noip模拟28 solutions
怎么说呢这个分数并不在我的意料范围之内
哈哈哈其实还不错,就是对于期望这一块,我理解的还是不够好
T1 遗忘之祭仪
说白了就是一个\(O(n^4)\)的算法,直接去跑一跑,过程中剪剪枝,然后复杂度就无限接近\(O(n2)\)了
但是这个出题人非常气人,你要特判一下符卡中啥也没有的情况,我就因为这个
浮点数例外
AC_code
#include<bits/stdc++.h>
using namespace std;
#define re register int
const int N=1005;
const int inf=0x3f3f3f3f;
int n,m,nm[N][N],sn;
int a,b,ab[N][N],sa,xf=inf,xs,yf=inf,ys;
int sum;
signed main(){
int T;scanf("%d",&T);
while(T--){
//cout<<T<<endl;
xf=inf;yf=inf;xs=0;ys=0;
sn=0;sa=0;
memset(nm,0,sizeof(nm));
memset(ab,0,sizeof(ab));
scanf("%d%d%d%d",&n,&m,&a,&b);
for(re i=1;i<=n;i++){
char x[N];
scanf("%s",x+1);
for(re j=1;j<=m;j++){
if(x[j]=='x'){
nm[i][j]=1,sn++;
}
}
}
for(re i=1;i<=a;i++){
char x[N];
scanf("%s",x+1);
for(re j=1;j<=b;j++){
if(x[j]=='x'){
ab[i][j]=1,sa++;
xf=min(xf,i);xs=i;
yf=min(yf,j);
ys=max(ys,j);
}
}
}
a=xs-xf+1;b=ys-yf+1;
if(n<a||m<b||a==0||b==0||sa==0){
printf("No\n");
continue;
}
for(re i=1;i<=a;i++)
for(re j=1;j<=b;j++)
ab[i][j]=ab[i+xf-1][j+yf-1];
if(sn%sa){
//cout<<"sb"<<endl;
printf("No\n");
continue;
}
for(re i=1;i<=n-a+1;i++){
for(re j=1;j<=m-b+1;j++){
int flag=0;
for(re x=1;x<=a;x++){
for(re y=1;y<=b;y++){
if(nm[i+x-1][j+y-1]!=ab[x][y]&&ab[x][y]){
flag=1;break;
}
}
if(flag)break;
}
if(flag)continue;
//sum++;
for(re x=1;x<=a;x++){
for(re y=1;y<=b;y++){
if(ab[x][y])nm[i+x-1][j+y-1]=0;
}
}
}
}
int flag=0;
for(re i=1;i<=n;i++)
for(re j=1;j<=m;j++)
if(nm[i][j])flag=1;
if(flag)printf("No\n");
else printf("Yes\n");
}
}
T2 客星璀璨之夜
我也知道这是那个最最最经典的小球进洞的题
但是吧,我就是不会,说白了就是傻
仔细想一想的话,你会发现,在这些星星们不断减少的过程中,其实每条路径的长度不变
这其实就可以开始转移没条路径的经过次数的期望了
直接从下面转移就好了,因为你的边是在一点一点的减少的哈哈哈,
就是代码啦,直接手摸一下数据就好了
AC_code
#include<bits/stdc++.h>
using namespace std;
#define re register int
#define ll long long
const int N=3005;
const ll mod=998244353;
ll n,m,a[N*2];
ll f[N][N*2];
ll ksm(ll x,ll y){
ll ret=1;
while(y){
if(y&1)ret=ret*x%mod;
x=x*x%mod;
y>>=1;
}
return ret;
}
ll ans,jc=1;
signed main(){
scanf("%lld",&n);m=2*n+1;
for(re i=1;i<=m;i++)scanf("%lld",&a[i]);
for(re i=1;i<=n;i++){
ll fi=ksm(i,mod-2),se=ksm(i*2,mod-2);
for(re j=2;j<=2*i+1;j++){
ll num=(i*2+1-j)/2;
if(j&1)f[i][j]=(f[i-1][j]*num%mod*fi%mod+f[i-1][j-1]*se%mod+f[i-1][j-2]*((i-num)*2-1)%mod*se%mod+se)%mod;
else f[i][j]=(f[i-1][j]*(num*2+1)%mod*se%mod+f[i-1][j-1]*se%mod+f[i-1][j-2]*((i-num-1))%mod*fi%mod+se)%mod;
}
}
for(re i=2;i<=m;i++){
ans=(ans+(a[i]-a[i-1])*f[n][i]%mod)%mod;
}
printf("%lld",ans);
}
T3 割海成路之日
所以这个题的并查集用的极其的妙
首先要维护两个并查集这事,肯定是个人都能想出来
所以我们直接维护好那些要经过3边的点的个数,在每一次更改的时候在增增减减
直接上代码
AC_code
#include<bits/stdc++.h>
using namespace std;
#define re register int
#define pa pair<int,int>
#define mpa(x,y) make_pair(x,y)
#define gc if(++ip==ie)fread(ip=buf,1,SZ,stdin)
const int SZ=1<<19;
char buf[SZ],*ie=buf+SZ,*ip=ie-1;
inline int read(){
int x;scanf("%d",&x);
return x;
/*gc;while(*ip<'-')gc;
bool f=*ip=='-';if(f)gc;
int x=*ip&15;gc;
while(*ip>'-'){x*=10;x+=*ip&15;gc;}
return f?-x:x;*/
}
const int N=3e5+5;
int n,m;
struct DJS{
int fa[N],siz[N];
DJS(){for(re i=1;i<=n;i++)fa[i]=i,siz[i]=1;}
int find(int x){return fa[x]==x?x:fa[x]=find(fa[x]);}
void add(int x,int y){
int fx=find(x);
int fy=find(y);
if(fx!=fy){
fa[fx]=fy;
siz[fy]+=siz[fx];
}
return ;
}
};
int to[N*2],nxt[N*2],val[N*2],head[N],rp;
void add_edg(int x,int y,int z){
to[++rp]=y;
val[rp]=z;
nxt[rp]=head[x];
head[x]=rp;
}
bool vis[N];
int fa[N],w[N];
void dfs(int x,int f,int v){
w[x]=v;fa[x]=f;
for(re i=head[x];i;i=nxt[i]){
int y=to[i];
if(y==f)continue;
dfs(y,x,val[i]);
}
}
int f[N];
signed main(){
//scanf("%d%d",&n,&m);
n=read();m=read();
DJS a,b;
for(re i=1,x,y,z;i<n;i++){
//scanf("%d%d%d",&x,&y,&z);
x=read();y=read();z=read();
add_edg(x,y,z);add_edg(y,x,z);
}
//cout<<"finish edge"<<endl;
dfs(1,0,0);
//cout<<"finish dfs"<<endl;
for(re i=1;i<=n;i++){
//cout<<w[i]<<endl;
if(w[i]==1)a.add(i,fa[i]);
if(w[i]!=3)b.add(i,fa[i]);
}
for(re i=1;i<=n;i++){
if(w[i]==3)f[a.find(fa[i])]+=b.siz[i];
}
//for(re i=1;i<=n;i++)cout<<f[i]<<endl;
for(re i=1,x,y,s,t;i<=m;i++){
//cout<<i<<endl;
scanf("%d%d%d%d",&x,&y,&s,&t);
if(fa[x]==y)swap(x,y);
if(w[y]==3){
f[a.find(x)]-=b.siz[y];
f[a.find(fa[b.find(x)])]+=b.siz[y];
b.add(y,x);
}
if(w[y]==2){
f[a.find(x)]+=f[y];
a.add(y,x);
}
if(w[y]!=1)w[y]--;
int flag=0,ans=0;
if(b.find(s)==b.find(t))flag=1;
if(a.find(s)==a.find(fa[b.find(t)]))flag=1;
if(b.find(fa[a.find(s)])==b.find(t))flag=1;
if(flag)printf("1 ");
else printf("0 ");
ans=b.siz[b.find(s)]+f[a.find(s)];
if(w[a.find(s)]==3)ans+=b.siz[b.find(fa[a.find(s)])];
printf("%d\n",ans);
}
}
QQ:2953174821