额。。。。有点坑:
A. Flipping Game
第一题的意思是说给你n个数,这些数是由0和1组成的,然后你可以采用一次操作:选择i和j之间的数x,把它变成1-x,也就是把0变成1,把1变成0.然后求在一次操作之后,最大的可能的1的个数有多少。不说话,直接爆搜走起:
#include <iostream>
#include <cstdio>
#include <string>
#include <string.h>
#include <map>
#include <vector>
#include <cstdlib>
#include <algorithm>
#include <cmath>
#include <queue>
#include <set>
#include <stack>
using namespace std;
int const N = 110;
int main()
{
int s[N];
int MAX = -1;
int sum;
int sum1;
int n;
int i,j,k;
while(scanf("%d",&n)!=EOF)
{
sum = 0;
for(i=0; i<n; i++)
{
scanf("%d",&s[i]);
sum += s[i];
}
for(i=0; i<n; i++)
{
for(j=i; j<n; j++)
{
sum1 = sum;
for(k=i; k<=j; k++)
{
sum1 -= s[k];
sum1 += (1-s[k]);
if(sum1>MAX) MAX = sum1;
}
}
}
printf("%d\n",MAX);
}
return 0;
}
B. Hungry Sequence
第一次直接没仔细读题,直接写了一个sp[i]= sp[i-1]+1(sp[i]%sp[i-1]!=0).果断WA了。后来仔细看,是i < j必须满足。n到2n输出...
#include <iostream>
#include <cstdio>
#include <string>
#include <string.h>
#include <map>
#include <vector>
#include <cstdlib>
#include <algorithm>
#include <cmath>
#include <queue>
#include <set>
#include <stack>
using namespace std;
int main()
{
int n,i;
cin >> n;
for(i=n; i< 2*n ; ++i)
printf("%d ", i);
printf("\n");
//printf("%d\n", 2*n-1);
return 0;
}
C. Magic Five
这道题应该用快速幂来求,若是对于项数很多的等比数列,因为求和公式中包含了除号,所以不能直接取mod,应该进行快速幂的转化
例如求sum=2^1+2^2+2^3+2^4+2^5+2^6+2^7 .......
共有n项
这是的公式就为 若n%2==0 T(n)=T(n/2)+T(n/2)*2^(n/2);
若n%2==1 T(n)=T(n/2)+T(n/2)*2^(n/2)+ 2^n;
对于此题来讲 先把所给的循环位上的和求出来,做为基底,然后利用快速幂上面的公式求解接可以了
因为比如说12507 12507 和为2^2+2^3+ 2^2*2^len+2^3*2^len == (2^2+2^3)+(2^2+2^3)*len;这样的话就可以直接把一个序列的和all当作基底来处理了...
(不过这个公式没有找到证明啊):
#include<stdio.h>
#include<iostream>
#include<string.h>
#include<algorithm>
#include<math.h>
#include<stdlib.h>
using namespace std;
const __int64 mod=1000000007;
__int64 all;
int Pow(__int64 n,int num) //快速幂求num^n
{
if(n==0)
return 1;
if(n==1)
return num;
__int64
tmp=Pow(n/2,num)%mod;
tmp=tmp*tmp%mod;
if(n%2==1)
tmp=tmp*num%mod;
return (int)tmp;
}
__int64 len;
int q;
int fun(int n)
{
if(n==1)
return all;
__int64 tmp=fun(n/2);
tmp = (tmp+tmp*Pow(n/2,q))%mod;
if(n%2==1)
tmp = ( tmp+Pow((n-1)*len,2)*all%mod )%mod;
return (int)tmp;
}
char a[2000000];
int main()
{
int n,ans;
while(scanf("%s",a)!=EOF)
{
cin>>n;
ans=0;
len=strlen(a);
q=Pow(len,2)%mod;
all=0;
for(int i=0; i<len; i++)
{
if(a[i]=='0'||a[i]=='5')
{
all=(all+Pow(i,2))%mod;
}
}
ans=fun(n);
cout<<ans<<endl;
}
return 0;
}
D. Block Tower
special judge。先把所有能建房子的地方全部建成绿色,因为红色要以蓝色为边才能建起来。所以我们先把能建蓝色的全部建成蓝色。然后在一蓝色为点DFS走入,向上下左右走,能联通的地方在回来的时候改建红色。
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<string>
#include<cmath>
using namespace std;
struct xl
{
int x,y;
char z;
} q[5000005];
char a[505][505];
int vis[505][505];
int dx[4]= {1,0,-1,0};
int dy[4]= {0,-1,0,1};
int n,m,i,j,len,k;
void dfs(int ans,int num)//暴搜
{
int i;
len++;
vis[ans][num]=1;
for(i=0; i<4; i++)
{
if(a[ans+dx[i]][num+dy[i]]=='.'&&vis[ans+dx[i]][num+dy[i]]==0)
{
dfs(ans+dx[i],num+dy[i]);
}
}
if(len > 1)//判断是否建红色建筑
{
q[k].x=ans;
q[k].y=num;
q[k].z='D';
k++;
q[k].x=ans;
q[k].y=num;
q[k].z='R';
k++;
a[ans][num]='R';
}
len--;
}
int main()
{
char c;
scanf("%d%d",&n,&m);
memset(vis,0,sizeof(vis));
for(i=1; i<=n; ++i)
{
c=getchar();
for(j=1; j<=m; ++j)
scanf("%c",&a[i][j]);
}
k = 0;
for(i = 1; i <= n; ++i)
{
for(j = 1; j <= m; ++j)
{
if(a[i][j]=='.')//建蓝色建筑
{
q[k].x=i;
q[k].y=j;
q[k].z='B';
k++;
}
}
}
for(i=1; i<=n; ++i)
{
for(j=1; j<=m; ++j)
{
if(vis[i][j]==0&&a[i][j]=='.')
{
len=0;
dfs(i,j);
}
}
}
printf("%d\n",k);
for(i=0; i<k; ++i)
{
printf("%c %d %d\n",q[i].z,q[i].x,q[i].y);
}
return 0;
}
E. Axis Walking
听闻是神DP,这。转来别人的解释:
给你一串数,从0开始,每次选某个数,然后向前移动ai长度,这里有些位置不能走,最后问你走到总长度的路有多少条。
小结:很裸的状压dp,不过得用sum数组优化下。
dp[i]=sum{dp[i^(1<<j]};i与j只相差一位,即i能通过i^(1<<j)增加aj转移过来。
#include<iostream>
#include<cstdio>
#define N 1000000007
#define maxn 1<<25
using namespace std;
int n,k;
int a[25],b[3],dp[maxn],sum[maxn];
int DP()
{
dp[0]=1;//只能从0开始
for(int i=1;i<(1<<n);i++)
{
//求出当前状态所在的位置
sum[i]=0;
int p;
for(int j=0;j<n;j++)
{
if(i&(1<<j))
{
p=j;//从小到大找第一个为1的位置
break;
}
}
sum[i]=sum[i^(1<<p)]+a[p];//去掉这个位置的状态一定已经访问过
//判断当前位置是否可以停留
int flag=0;
for(int j=0;j<k;j++)
{
if(sum[i]==b[j])
{
flag=1;
break;
}
}
//不可以的话,直接忽略,当前的路径和为0
if(flag==1) continue;
//动态转移
for(int j=0;j<n;j++)
{
if(i&(1<<j))
{
dp[i]+=dp[i-(1<<j)];
if(dp[i]>N)//这里没用%
dp[i]-=N;
}
}
}
return dp[(1<<n)-1];
}
int main()
{
scanf("%d",&n);
for(int i=0;i<n;i++)
{
scanf("%d",&a[i]);
}
scanf("%d",&k);
for(int i=0;i<k;i++) scanf("%d",&b[i]);
printf("%d\n",DP());
return 0;
}