您的位置:首页 > 其它

CodeForce#191 Div2

2013-07-12 12:43 295 查看
POJ感觉刷的差不多了,剩下的题里面好多都是08年以前的陈题,参考意义已经不打了。然后根据队友推荐,开始做CF,CF还是不错的,有代码,有解题报告,有数据,很强大!

这次做的是#191 Div2的题解:

Problem A
Flipping Game(枚举)

题意:给你01序列,选出一段区间,把0变1,1变0,求最后最多有几个1.

题解:作为第一题,数据也不是太大,可以直接暴力枚举过。

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=105;
int sum[2]
,a
;
int main()
{
int n;
while(scanf("%d",&n)!=EOF)
{
bool flag=false;
sum[0][0]=sum[1][0]=0;
for(int i=1;i<=n;i++)
{
scanf("%d",&a[i]);
sum[a[i]][i]=sum[a[i]][i-1]+1;
sum[1-a[i]][i]=sum[1-a[i]][i-1];
if(a[i]==0)flag=true;
}
if(!flag)
printf("%d\n",sum[1]
-1);
else
{
int ans=0;
for(int i=1;i<=n;i++)
for(int j=i;j<=n;j++)
{
int cnt0=sum[0][j]-sum[0][i-1],cnt1=sum[1][j]-sum[1][i-1];
ans=max(ans,cnt0+sum[1][i-1]+sum[1]
-sum[1][j]);
}
printf("%d\n",ans);
}
}
return 0;
}


Problem B
Hungry Sequence(构造)
题意:输入n(n<=10^5),求一个序列(序列每个元素都必须小于10^7),是的后面的不会是前面的倍数。

题解:直接质数序列就行了,话说回来,如果n再大一点,或者元素限制更多一些,又该怎么做。

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int mr=10000001;
bool notp[mr];
int pr[670000];
int pn;
void getpri()//筛素数
{
pn=0;
memset(notp,0,sizeof(notp));
for(int i=2; i<mr&&pn<=100002; i++)
{
if(!notp[i])
{
pr[pn++]=i;
}
for(int j=0; j<pn && i*pr[j]<mr; j++)
{
int k=i*pr[j];
notp[k]=1;
if(i%pr[j]==0)
{
break;
}
}
}
}
int main()
{
getpri();
int n;
while(scanf("%d",&n)!=EOF)
{
for(int i=0;i<n;i++)
printf("%d%c",pr[i],(i==n-1)?'\n':' ');
}
return 0;
}


Problem C
Magic Five(组合数学)

题意:给你数字序列a以及一个数k,(1<=|a|<=10^5,1<=k<=10^9),最后要处理的是数字序列aaaaa...aaaa(就是拷贝a序列k次),处理方式就是从中删除一些数字,使得最后得到结果%5=0,并且可以有leading zero,最后当然还要mod 10^+7。

题解:

mod 5=0就是说要以0或5结尾

找a中0,5的位置,若以它结尾,那么方法就有2^len中,len就是前面元素的总长度,从最右边的a开始,每个相邻a对应位置的0或5的len都是相差|a|的

如果记a序列中0,5的位置是b1,b2,b2...bm,答案就是2^(|a|*(k-1))*(2^b1+2^b2+2^b3...+2^bm)+2^(|a|*(k-2))*(2^b1+2^b2+2^b3...+2^bm)....+2^0*(2^b1+2^b2+2^b3...+2^bm)

记T=(2^b1+...2^bm),上面就可以表示为T*(2^0+2^|a|+2^2|a|+....2^(k-1)|a|)

后面是等比数列,记2^|a|=q套用求和公式就是(q^k-1)/(q-1),有取模运算,所以除以(q-1)变成乘以(q-1)的逆元

前面的T,就是逐位统计就行了

这里需要注意,由于a的长度也很大,所以快速幂取模会超时的,考虑到底数全是2,所以可以把2^(2^x)打个表就行了。

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long ll;
const ll mod=1000000007;
ll pow2[1005];
void init()
{
pow2[0]=2;
for(int i=1;i<=1000;i++){
pow2[i]=pow2[i-1]*pow2[i-1];
if(pow2[i]>=mod)pow2[i]%=mod;
}
}
ll mulmod(ll a, ll b)//a*b%m 避免高精度计算
{
if(a<0)a=a%mod+mod;
else a=(a>=mod)?a%mod:a;
if(b<0)b=b%mod+mod;
else b=(b>=mod)?b%mod:b;
ll re = 0;
while(b)
{
if (b&1) re = (re + a)%mod;
a = (a << 1)%mod;
b >>= 1;
}
return re;
}
ll fastmod(ll a,ll b)//a^b %m 注意可能要用long long时用long long
{
ll re = 1, y = (a>=mod)?a%mod:a;
for(; b; b>>=1, y = mulmod(y, y))
if (b&1)re = mulmod(y, re);
return re;
}
ll fastmod(ll len)
{
ll ans=1;
int k=0;
while(len>0)
{
if(len&1ll){
ans=ans*pow2[k];
if(ans>=mod)ans%=mod;
}
len>>=1;
k++;
}
return ans;
}
char s[100005];
ll egcd(ll a, ll b, ll &x, ll &y)
{
if (b==0)
{
x=1ll,y=0ll;
return a;
}
ll d, tp;
d = egcd (b, a%b, x, y);
tp = x;
x = y;
y = tp - a/b*y;
return d;
}
ll getni(ll a)
{
ll x,y,d;
d=egcd(a,mod,x,y);
return x;
}
int main()
{
init();
while(scanf("%s",s)!=EOF)
{
ll ans,k,t;
int len=strlen(s);
scanf("%I64d",&k);
t=0;
for(int i=len-1;i>=0;i--)
if(s[i]=='0'||s[i]=='5')
{
t=(t+fastmod((ll)i));
if(t>=mod)t%=mod;
}
ans=mulmod(t,fastmod((ll)len*k)-1ll);
ans=mulmod(ans,getni(fastmod(len)-1));
printf("%I64d\n",ans);
}
return 0;
}


Problem D
Block Tower(dfs+构造)
题意:n*m格子上修塔,Red 塔权值比 Blue塔高,但是修建Red塔必须现在旁边修Blue塔,可以随意拆除,并且不会影响其他塔。然后格子上有些地方不能修塔,求最大权的修法。

题解:一个连通分量里面,可以保证最后只有一个Blue塔,其他全是Red,方法就是以某个点作为根,访问一个点的方式就是,一进去就修成Blue塔,然后访问儿子,然后如果该节点是root就不管,否则就拆了修Red塔。

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=505;
struct data{
int k,x,y;
data(){}
data(int _k,int _x,int _y){k=_k,x=_x,y=_y;}
void show()
{
printf("%c %d %d\n",(k==0)?'D':((k==1)?'B':'R'),x,y);
}
}res[N*N*4];
char map

;
int mark

;
int dr[][2]={
0,1,
0,-1,
-1,0,
1,0
};
int row,col,top;
bool ok(int x,int y)
{
return x>=1&&x<=row&&y>=1&&y<=col&&mark[x][y]==0;
}
void dfs(int x,int y,int rx,int ry)
{
res[top++]=data(1,x,y);
mark[x][y]=1;
for(int i=0;i<4;i++)
{
int tx=x+dr[i][0],ty=y+dr[i][1];
if(ok(tx,ty)){
dfs(tx,ty,rx,ry);
}
}
if(rx!=x||ry!=y){
res[top++]=data(0,x,y);
res[top++]=data(2,x,y);
mark[x][y]=2;
}
}
int main()
{
while(scanf("%d%d",&row,&col)!=EOF)
{
memset(mark,-1,sizeof(mark));
for(int i=1;i<=row;i++)
{
scanf("%s",map[i]+1);
for(int j=1;j<=col;j++)
{
if(map[i][j]=='.')
mark[i][j]=0;
}
}
top=0;
for(int i=1;i<=row;i++)
{
for(int j=1;j<=col;j++)
{
if(mark[i][j]==0)
{
dfs(i,j,i,j);
}
}
}
printf("%d\n",top);
for(int i=0;i<top;i++)
res[i].show();
}
return 0;
}


Problem E
Axis Walking(DP)
题意:n个数,有n!全排,其中有一些会使得sum(i)等于给定的某个数,这种方案是不合要求方案,问最后有多少方案。

题解:位压缩,mask中有1代表选了a[i]这个数,sum[mask]代表他们的和,dp[mask]代表mask中合理路的种数。这题,也想了好久,老是TLE,最后与watashi的代码对拍发现由于自己是正推得到后面的,貌似是这样找0是O(n)的,但如果逆推,找1是O(1)的,因为有lowbit这函数,这样做就AC了。只是,貌似watashi的找1也是用的枚举啊,,为啥我前面的代码没过。。

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int mod=1000000007;
const int MAX=(1<<25)+1;
int a[30],neq[2],n,dp[MAX],sum[MAX];
int main()
{
//freopen("data.txt","r",stdin);
while(scanf("%d",&n)!=EOF)
{
for(int i=0;i<n;i++)scanf("%d",&a[i]);
int sk,mx=1<<n;
scanf("%d",&sk);
neq[0]=neq[1]=-2;
for(int i=0;i<sk;i++)scanf("%d",&neq[i]);
memset(dp,0,sizeof(dp));
memset(sum,-1,sizeof(sum));
dp[0]=1,sum[0]=0;
for(int i=1;i<mx;i++){
int j=__builtin_ctz(i);
int tp=sum[i]=sum[i^(1<<j)]+a[j];
if(tp==neq[0]||tp==neq[1])dp[i]=-1;
}
for(int i=1;i<mx;i++){
if(dp[i]==-1)
dp[i]=0;
else{
dp[i]=0;
int res;
for(int j=i;j!=0;j=j-(j&-j)){
res=(i^(j&-j));
dp[i]+=dp[res];
if(dp[i]>=mod)dp[i]-=mod;
}
}
}
printf("%d\n",dp[mx-1]);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: