您的位置:首页 > 其它

czl蒻蒟的OI之路16

2017-10-08 21:00 127 查看
XJOI奋斗群蒻蒟群群赛17 RANK排名9

T1Increasing SequenceTLE一次AC

题意

分析过程

给出题解

T2Jumping JackWA一次后AC

题意

分析过程

给出题解

T3How Many Squares 已AC

题意

分析过程

给出题解

T4A Simple TaskWA两次之后AC

题意

分析过程

给出题解

T5

题意

分析过程

给出题解

—>XJOI奋斗群(蒻蒟群)群赛17<— RANK排名9

T1:Increasing Sequence(TLE一次AC)

题意:

给你一个数列,然后给出你一个数d,数列中的每个数都可以加上d,问你最少加上几次d,能够使这个数列变成一个增序序列。

分析过程:

只要每碰到一个数比前一个数小,就加上一定的值直到大于前一个数,最后输出次数就行了。

给出题解:

#include<bits/stdc++.h>
using namespace std;

int main()
{
int n,d;
int a[5000];
scanf("%d%d",&n,&d);
for(int i=1;i<=n;i++)
{
scanf("%d",&a[i]);
}
long long  cnt=0;
for(int i=2;i<=n;i++)
{
if(a[i]<=a[i-1])
{
int dif=a[i-1]-a[i];
dif/=d;
dif++;
a[i]+=d*dif;
cnt+=dif;
}
else continue;
}
printf("%d\n",cnt);
return 0;
}


T2:Jumping Jack(WA一次后AC)

题意:

一个人在练习跳跃,第一次只能跳一个单位,之后每一次跳就能够比前一次长一个单位,问你经过多少次跳跃之后能够准确地到达x这个位置。

分析过程:

由于x的值可能是正的也可能是负的,所以要先把x取绝对值。先预估sqrt(2*x)的值作为cnt的预估值,然后再从这个值开始向答案推进。

给出题解:

#include<bits/stdc++.h>
using namespace std;
int main()
{
int x;
scanf("%d",&x);
x=abs(x);
int cnt=sqrt(2*x);
while(cnt*(cnt+1)/2<x||(cnt*(cnt+1)/2-x)&1)
cnt++;
printf("%d\n",cnt);
return 0;
}


T3:How Many Squares? (已AC)

题意:

给你一个矩阵,问你其中有几个正方形,要求正方形旁边不能有多与的边。

分析过程:

先便利每个数组中的

给出题解:

#include<bits/stdc++.h>
using namespace std;
int dic[8][2]= {{0,1},{1,0},{0,-1},{-1,0},{1,1},{1,-1},{-1,1},{-1,-1}};
char a[255][255];
int len=0;
int n,m;

void judge(int x,int y)
{
if(x<0||x>=n||y<0||y>=m||a[x][y]!='1')return ;
a[x][y]='2';
len++;
for(int i=0; i<8; i++)
{
judge(x+dic[i][0],y+dic[i][1]);
}
}

bool solve(int x,int y,int len,int l,int r)
{
for(int i=0; i<len+1; i++)
for(int j=l; j<r; j++)
{
if(x+dic[j][0]*i<0||x+dic[j][0]*i>=n||y+dic[j][1]*i<0||y+dic[j][1]*i>=m||a[x+dic[j][0]*i][y+dic[j][1]*i]!='2')
return 0;
}
return 1;
}

int main()
{
int T;
scanf("%d",&T);
while(T--)
{
scanf("%d%d",&n,&m);
for(int i=0; i<n; i++)
scanf("%s",a[i]);
int res=0;
for(int i=0; i<n; i++)
for(int j=0; j<m; j++)
{
if(a[i][j]=='1'
bc20
)
{
len=0;
judge(i,j);
if(len%4)continue;
res+=solve(i,j,len/4,0,2)&&solve(i+len/4,j+len/4,len/4,2,4);
res+=solve(i,j,len/4,4,6)&&solve(i+len/2,j,len/4,6,8);
}
}
printf("%d\n",res);
}
return 0;
}


T4:A Simple Task(WA两次之后AC)

题意:

给你一个简单的无向图,让你统计其中环的个数。

分析过程:

我们设计一个状态{[s][SET][i]}来记录起点s到终点i的简单路径的条数,其中SET表示经过的节点的集合。但由于圆排列的性质,这样的状态是有重复的。我们通过指定起点为SET中的最小序号点来消除圆排列带来的重复,状态变为{[SET][i]}。还要注意,即使这样定义状态,计算简单环个数的时候仍会将2个节点一条单边的情况当成环,也会将长度大于2的环正向计算一遍,反向计算一遍。所以我们还要进行后处理。

前向的状态转移方程可以写作:

dp[SET][j]=∑(i∈SET,i−j)dp[SET][i]

但这样的方程并不利于统计简单环的个数。

后向的状态转移方程可以写作:

设简单环的个数用统计量cnt表示。对于dp[SET][i]状态,i的每一条边eij,j∈neighbor(i):若j∈SET则说明遇到了环,dp[SET][i]贡献给cnt;若j∉SET则说明获得一条简单路径,dp[SET][i]贡献给dp[SET′][j]。

后处理:

由于长度为2的简单环被统计了进去,所以cnt−m;又由于长度大于2的简单环被统计了2遍,所以(cnt−m)/2。

最后要注意环的个数可能会达到19!个,所以我们需要用int64(之前被这个卡了好久)。

给出题解:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;

ll n,m,ans,tot;
ll tmap[20][20],f[1<<19][19];

ll get_p(int a)
{
for(int i=0; i<n; i++)
{
if(a&(1<<i)) return i;
}
}
ll solve()
{
ll i,j,k,p,s;
ans=0;
tot=(1<<n)-1;
memset(f,0,sizeof f);
for(i=0; i<n; i++)
{
//      printf("%d %d\n",1<<i,i);
f[1<<i][i]=1;
}
for(i=1; i<=tot; i++)
{
for(j=0; j<n; j++)
{
if(f[i][j]==0) continue ;
p=get_p(i);
for(k=p; k<n; k++)
{
if(j==k) continue ;
if(tmap[j][k]==0)continue;
if(i&(1<<k))
{
if(k==p) ans+=f[i][j];
}
else
{
s=i|(1<<k);
f[s][k]+=f[i][j];
}
}
}
}
ans-=m;
ans/=2;
return ans;
}
int main()
{
scanf("%I64d%I64d",&n,&m);
memset(tmap,0,sizeof tmap);
ll u,v;
for(int i=1; i<=m; i++)
{
scanf("%I64d%I64d",&u,&v);
tmap[u-1][v-1]=tmap[v-1][u-1]=1;
}
ll res=solve();
printf("%I64d\n",res);
return 0;
}
}


T5:

题意:

分析过程:

给出题解:
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: