day3
模拟赛,看了看a组题,发现是博弈论,非常开心(因为好玩),于是做的a组。结果差点爆零,死命纠结t1的sg函数,但其实只是一个dp,不用扯到sg函数的那种。
t1:
就是dp,f[i][j]表示第i个动物报数最大为j是否必胜。然后加一个后缀和(应该能叫后缀和吧)(或者说区间和?)优化。
中间还wa了一次,因为在处理s数组时减去的那个f数组越界了,需要特判一下。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int n,m,kk;
int f[10010][5010],a[10010],s[10010][5010];
int main()
{
freopen("vode.in","r",stdin);
freopen("vode.out","w",stdout);
scanf("%d%d%d",&n,&m,&kk);
for(int i=1;i<=n;i++)
scanf("%d",&a[i]);
int p=1;
for(int i=n+1;i<=n+m;i++)
{
if(p>n)
p=1;
a[i]=a[p];
p++;
}
for(int i=n+m-1;i>=1;i--)
for(int j=m-1;j>=1;j--)
{
if(a[i]==a[i+1])
{
s[i][j]=s[i][j+1];
if(j+kk<m)
s[i][j]-=f[i][j+kk];
if(s[i+1][j+1]>0)
{
f[i][j]=1;
s[i][j]++;
}
}
else
{
s[i][j]=s[i][j+1];
if(j+kk<m)
s[i][j]-=f[i][j+kk];
if(s[i+1][j+1]==0)
{
f[i][j]=1;
s[i][j]++;
}
}
}
for(int i=1;i<=n;i++)
for(int j=1;j<=kk;j++)
if(f[i][j])
{
printf("%d ",a[i]);
break;
}
else if(j==kk)
{
printf("%d ",a[i]^1);
}
fclose(stdin);
fclose(stdout);
return 0;
}
不想改a组了,先写了一个b组t3玩。
就是把式子化简一下,设比值为k,然后会发现T=(2K-2)/(2K-1)*N,我们要让t为正整数,同时(2K-2)/(2K-1)又不能为一,2k-1就一定为n的因子。k为正整数,所以2k-1为奇数,然后就可以n½枚举找n的奇因子了。注意一下2k-2不能为零,也就是2k-1不能为1。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
long long n,a[1000010],cnt;
int main()
{
freopen("math.in","r",stdin);
freopen("math.out","w",stdout);
scanf("%lld",&n);
long long sn=sqrt(n);
for(long long i=1;i<=sn;i++)
if(!(n%i))
{
if((i%2)&&i!=1)
a[++cnt]=(n/i)*(i-1);
if((n/i)%2&&(n/i)!=1)
a[++cnt]=i*(n/i-1);
}
cout<<cnt<<" ";
sort(a+1,a+1+cnt);
for(int i=1;i<=cnt;i++)
printf("%lld ",a[i]);
fclose(stdin);
fclose(stdout);
return 0;
}
然后我终于改了a组t2:
我当时打了bfs,然后愉悦爆零。哇的一下哭出声。
这个题是把每一个非墙点与相邻点连边权为1的边,然后找到四个方向的墙,连一条边权为min(dis(此点,墙边传送门的点))+1的边(其实和最近的传送门点应该连边权为dis的边,但可以从边权为1的边走过去,不影响答案)。然后跑spfa,求起点到终点最短路即可。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
using namespace std;
int n,m,s,t,cnt,head[250010],dis[250010],vis[250010];
char mp[510][510];
struct Edge
{
int v,nxt,val;
}e[10000010];
void add(int u,int v,int val)
{
e[++cnt].v=v;
e[cnt].nxt=head[u];
e[cnt].val=val;
head[u]=cnt;
}
int num(int x,int y)
{
return (x-1)*m+y;
}
void spfa()
{
memset(dis,0x3f3f3f3f,sizeof(dis));
queue<int>q;
dis[s]=0;
vis[s]=1;
q.push(s);
while(!q.empty())
{
int u=q.front();
q.pop();
vis[u]=0;
for(int i=head[u];i;i=e[i].nxt)
{
int v=e[i].v;
if(dis[v]>dis[u]+e[i].val)
{
dis[v]=dis[u]+e[i].val;
if(!vis[v])
{
q.push(v);
vis[v]=1;
}
}
}
}
}
int main()
{
freopen("portal.in","r",stdin);
freopen("portal.out","w",stdout);
cin>>n>>m;
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
{
cin>>mp[i][j];
if(mp[i][j]=='C')
s=num(i,j);
else if(mp[i][j]=='F')
t=num(i,j);
}
for(int i=2;i<n;i++)
for(int j=2;j<m;j++)
if(mp[i][j]!='#')
{
int x1=i,x2=i,y1=j,y2=j;
int mindis=0x3f3f3f3f;
while(mp[x1+1][j]!='#')
x1++;
while(mp[x2-1][j]!='#')
x2--;
while(mp[i][y1+1]!='#')
y1++;
while(mp[i][y2-1]!='#')
y2--;
mindis=min(x1-i,min(i-x2,min(y1-j,j-y2)));
mindis++;
add(num(i,j),num(x1,j),mindis);
add(num(i,j),num(x2,j),mindis);
add(num(i,j),num(i,y1),mindis);
add(num(i,j),num(i,y2),mindis);
if(mp[i+1][j]!='#')
add(num(i,j),num(i+1,j),1);
if(mp[i-1][j]!='#')
add(num(i,j),num(i-1,j),1);
if(mp[i][j+1]!='#')
add(num(i,j),num(i,j+1),1);
if(mp[i][j-1]!='#')
add(num(i,j),num(i,j-1),1);
}
spfa();
if(dis[t]==0x3f3f3f3f)
cout<<"nemoguce";
else
cout<<dis[t];
fclose(stdin);
fclose(stdout);
return 0;
}
其实题目不是不可做,就是考试死活想不到正路上......dalao炒鸡多啊我的天,orz。
然而我还是改完了t3:
并查集,按秩合并,把时间赋为点权(我之前纠结了半天怎么连边权2333),在并查集树上找max点权就行。
re了好几次,最后发现freopen文件名打错了......
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int n,m,q,fa[100010],dep[100010],siz[100010],tim[100010],x,y;
int find_fa(int x)
{
if(fa[x]==x)
return x;
return find_fa(fa[x]);
}
void update(int x)
{
if(fa[x]==x)
return;
update(fa[x]);
dep[x]=dep[fa[x]]+1;
}
int query(int a,int b)
{
int res=0;
if(dep[a]<dep[b])
swap(a,b);
while(dep[a]>dep[b])
{
res=max(res,tim[a]);
a=fa[a];
}
while(a!=b)
{
res=max(res,max(tim[a],tim[b]));
a=fa[a];
b=fa[b];
}
return res;
}
int main()
{
freopen("pictionary.in","r",stdin);
freopen("pictionary.out","w",stdout);
scanf("%d%d%d",&n,&m,&q);
for(int i=1;i<=n;i++)
fa[i]=i,siz[i]=1;
for(int i=1;i<=m;i++)
{
int r=n/(m-i+1);
int p=m-i+1;
for(int j=2;j<=r;j++)
{
int f1=find_fa(p*(j-1));
int f2=find_fa(p*j);
if(f1!=f2)
{
if(siz[f1]<siz[f2])
swap(f1,f2);
fa[f2]=f1;
tim[f2]=i;
siz[f1]=max(siz[f1],siz[f2]+1);
}
}
}
for(int i=1;i<=n;i++)
update(i);
for(int i=1;i<=q;i++)
{
scanf("%d%d",&x,&y);
printf("%d
",query(x,y));
}
fclose(stdin);
fclose(stdout);
return 0;
}