A. Protect Sheep: 地图上有羊有狼,需要在空白处放狗将羊和狼分隔开。
羊和狼有相邻的时候肯定搞不定,否则……只需要……把所有的空地……都放上狗。(○` 3′○)
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<cctype>
#include<queue>
#include<map>
#include<set>
#include<stack>
#include<vector>
#include<iostream>
#include<algorithm>
#define maxn 556
#define maxm 1050
#define INF 0x3f3f3f3f
#define eps 1e-8
const int mod = 1e6;
using namespace std;
typedef long long ll;
int n,m;
char maze[maxn][maxn];
int pos[4][2]={1,0,0,1,-1,0,0,-1};
bool judge(int x,int y)
{
if(x>=0&&y>=0&&x<n&&y<m)
return true;
return false;
}
int main()
{
scanf("%d%d",&n,&m);
bool flag=false;
for(int i=0;i<n;i++)
scanf("%s",maze[i]);
for(int i=0;i<n;i++)
{
for(int j=0;j<m;j++)
{
if(maze[i][j]=='S')
{
for(int k=0;k<4;k++)
{
int x=i+pos[k][0];
int y=j+pos[k][1];
if(judge(x,y)&&maze[x][y]=='W')
{
flag=true;
break;
}
}
}
if(flag)break;
}
}
if(flag)
printf("No\n");
else
{
printf("Yes\n");
for(int i=0;i<n;i++)
{
for(int j=0;j<m;j++)
{
if(maze[i][j]=='.')
printf("D");
else printf("%c",maze[i][j]);
}
printf("\n");
}
}
return 0;
}
B. Primal Sport: 定义对于一个>=3的整数x的变换:找出小于x的一个素数a,将x变为不小于x的a的最小的倍数。已知某正整数经两次变换后的结果,求这个数可能的最小值。
设pre(x)为x的最大素因子,则可知,当且仅当整数在[x-pre(x)+1,x]范围内时,整数的变换值为x。则可对于给出的X2,暴力枚举X1的范围[X2-pre(X2)+1,X2],找出其中X0=X1-pre(X1)+1的最小值。使用素数筛不仅可以标记非素数,还可以同时标记最大素因子。
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<cctype>
#include<queue>
#include<map>
#include<set>
#include<stack>
#include<vector>
#include<iostream>
#include<algorithm>
#define maxn 1000050
#define INF 0x3f3f3f3f
#define eps 1e-8
const int mod = 1e6;
using namespace std;
typedef long long ll;
int n,no;
bool vis[maxn];
int pre[maxn];
void init()
{
no=0;
for(int i=2;i<=n;i++)
{
if(!vis[i])
{
for(int j=2*i;j<=n;j+=i)
{
vis[j]=1;
pre[j]=i;
}
}
}
}
int main()
{
scanf("%d",&n);
init();
int tmp=pre[n];
int ans=INF;
for(int i=n;i>n-tmp;i--)
ans=min(ans,i-pre[i]+1);
printf("%d\n",ans);
return 0;
}
C. Producting Snow: 在第i天制造一个体积为vi的雪人,同时每个雪人都会融化ti的体积,求每一天中融化的总体积。
普通的O(n^2)处理肯定是不行了。对于每一天的雪人,我们都要计算出在哪一天它会全部融化,然后将这一天的总体积加上相应的数值。遍历所有的雪人必然是O(n)的复杂度,这就要求计算和更新时间内都得在O(logn)的复杂度内完成。考虑到时间更新必然是在一个连续的时间区间里,可以维护t[i]的前缀和,对于第i个雪人二分找出它完全融化的时间k,用一个树状数组维护第i天中整天融化的雪人数,再单独维护第k天融化量小于t[i]的余数。这之中有一个问题:在n天结束时雪人并不一定会融化完。对于用lower_bound找出的k,树状数组上应更新i~k-1时间。而对于第k天,当i<=k时(这是为了避免v[i]=0的情况,v[i]=0时i会小于k,无需更新k),若v[i]+sum[i-1]<=sum[k],即在第k天可以化完,更新量cnt[k]+=(v[i]+sum[i-1]-sum[k-1]),否则就只能cnt[i]+=t[i],在第i天达到了最大融化量仍未化完。最终第i天的总融化量即为tree[i]*t[i]+cnt[i]。
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<cctype>
#include<queue>
#include<map>
#include<set>
#include<stack>
#include<vector>
#include<iostream>
#include<algorithm>
#define maxn 100050
#define INF 0x3f3f3f3f
#define eps 1e-8
const int mod = 1e9 + 7;
using namespace std;
typedef long long ll;
int n;
ll v[maxn], t[maxn];
ll sum[maxn], cnt[maxn];
int tree[maxn];
int lowbit(int x) { return x&(-x); }
void add(int x, int w)
{
while (x <= n)
{
tree[x] += w;
x += lowbit(x);
}
return;
}
int query(int x)
{
int ans = 0;
while (x > 0)
{
ans += tree[x];
x -= lowbit(x);
}
return ans;
}
int main()
{
scanf("%d", &n);
for (int i = 1; i <= n; i++)
scanf("%I64d", &v[i]);
for (int i = 1; i <= n; i++)
{
scanf("%I64d", &t[i]);
sum[i] = sum[i - 1] + t[i];
}
memset(tree, 0, sizeof(tree));
for (int i = 1; i <= n; i++)
{
int k = lower_bound(sum + 1, sum + n + 1, v[i] + sum[i - 1]) - sum;
if (i < k)add(i, 1), add(k, -1);
if (i <= k)
{
if (v[i] + sum[i - 1] > sum[k])cnt[k] += t[i];
else cnt[k] += (v[i] + sum[i - 1] - sum[k - 1]);
}
}
for (int i = 1; i <= n; i++)
{
int tmp = query(i);
printf(i == n ? "%I64d\n" : "%I64d ", t[i] * tmp + cnt[i]);
}
return 0;
}