Codeforces Round #470 (rated, Div. 2, based on VK Cup 2018 Round 1)題解
阿新 • • 發佈:2018-12-30
A. Protect Sheep
只要wolf的四鄰接格子中沒有sheep,則肯定有辦法放狗使得狼無法接觸到羊,把所有空格替換成狗就行了。
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=505;
const int maxm=100005;
const int maxe=200005;
const int mod=1e9+7;
int n,m;
char ma[maxn][maxn];
int dx[4]={-1,0,0,1};
int dy[4]={0,-1,1,0};
int main(){
scanf ("%d%d",&n,&m);
for(int i=0;i<n;i++){
scanf("%s",ma[i]);
}
bool f=1;
for(int i=0;i<n;i++){
for(int j=0;j<m;j++){
if(ma[i][j]=='W'){
for(int k=0;k<4;k++){
int nx=i+dx[k];
int ny=j+dy[k];
if (nx<0||nx>=n)continue;
if(ny<0||ny>=m)continue;
if(ma[nx][ny]=='S'){f=0;break;}
}
}
if(f==0)break;
}
if(f==0)break;
}
if(f==0){printf("No\n");return 0;}
printf("Yes\n");
for(int i=0;i<n;i++){
for (int j=0;j<m;j++){
if(ma[i][j]=='.')ma[i][j]='D';
}
}
for(int i=0;i<n;i++){
printf("%s\n",ma[i]);
}
return 0;
}
B. Primal Sport
首先處理處所有質數。
思路是先找出每個數作為X1的情況下,X0的最小值是多少,然後對於x2遍歷它的每個素因子,確定x1的取值範圍,然後就遍歷那個取值範圍找出答案最小值。
1.確定每個x1對應的x0最小值的方法就是:用每個質數去更新它的倍數a=k*prime(k>=2),x0[a]=min(x0[a],prime*(k-1)+1)
2.最終確定的x1的取值範圍肯定是一段連續的區間(k to n),確定範圍的方法類似(1)
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=1000005;
const int maxm=100005;
const int maxe=200005;
const int mod=1e9+7;
int n,m;
int prime[maxn];
int tot;
bool vis[maxn];
void init(){
tot=0;
for(int i=2;i<maxn;i++){
if(vis[i])continue;
prime[tot++]=i;
for(int j=2;j*i<=maxn;j++){
vis[j*i]=1;
}
}
}
int pre[maxn];
int main(){
init();
scanf("%d",&n);
memset(pre,0x3f,sizeof(pre));
for(int i=0;i<tot;i++){
int num=prime[i];
for(int j=2;j*num<=n;j++){
pre[j*num]=min(pre[j*num],(j-1)*num+1);
}
}
int ans=0x3f3f3f3f;
int cnt=n;
for(int i=tot-1;i>=0;i--){
if(prime[i]>=n)continue;
if(n%prime[i])continue;
int pos=((n/prime[i])-1)*prime[i]+1;
while(cnt>=pos){
ans=min(ans,pre[cnt]);
cnt--;
}
}
printf("%d\n",ans);
return 0;
}
C. Producing Snow
考慮每天新增雪對後面每一天的融化數量的貢獻,發現第i天的雪在第k天融化完,則它對第i到k-1天的貢獻都是t[j],對第k天的貢獻就是剩餘的雪的數量。
所以二分雪到第幾天剛好融化完,然後用類似字首和的方式對區間打標記處理一下即可。
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=101005;
const int maxm=100005;
const int maxe=200005;
const int mod=1e9+7;
int n,m;
ll v[maxn];
ll t[maxn];
ll sum[maxn];
ll a[maxn];
ll ans[maxn];
int main(){
scanf("%d",&n);
for(int i=1;i<=n;i++)scanf("%lld",&v[i]);
for(int i=1;i<=n;i++)scanf("%lld",&t[i]);
for(int i=1;i<=n;i++){
sum[i]=sum[i-1]+t[i];
}
for(int i=1;i<=n;i++){
int pos=lower_bound(sum+i,sum+n+1,v[i]+sum[i-1])-sum;
ans[pos]+=v[i]+sum[i-1]-sum[pos-1];
a[i]++;
a[pos]--;
}
for(int i=1;i<=n;i++){
a[i]+=a[i-1];
ans[i]+=a[i]*t[i];
}
for(int i=1;i<=n;i++){
printf("%lld ",ans[i]);
}
return 0;
}
D. Perfect Security
暴力一點就是n方的,肯定超時的做法。
異或就可以按位考慮,每個數想要異或之後變得更小,肯定是異或一個二進位制位最為相似且不同位儘量少且儘量在低位的,所以建棵字典樹用來查詢即可,把每個數字變成一個三十位的二進位制字串插入到trie上就行了,涉及到刪除操作開一個計數陣列即可。
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define MP make_pair
const int maxn=300005;
const int maxm=(1<<25);
int n,m;
int a[maxn],p[maxn];
int ch[maxm][2];
int cou[maxm];
int sz;
void inser(int num){
int u=0;
for(int i=30;i>=0;i--){
int c=0;
if((1<<i)&num)c=1;
if(!ch[u][c]){
ch[sz][0]=ch[sz][1]=0;
cou[sz]=0;
ch[u][c]=sz++;
}
cou[u]++;
u=ch[u][c];
}
cou[u]++;
}
void build(){
for(int i=0;i<n;i++){
inser(p[i]);
}
}
int cal(int num){
int num1=num;
int u=0;
for(int i=30;i>=0;i--){
int c=0;
if((1<<i)&num)c=1;
if(!ch[u][c]||!cou[ch[u][c]]){
c=1-c;
}
num1^=(c<<i);
cou[u]--;
u=ch[u][c];
}
cou[u]--;
return num1;
}
int main(){
scanf("%d",&n);
for(int i=0;i<n;i++)scanf("%d",&a[i]);
for(int i=0;i<n;i++)scanf("%d",&p[i]);
sz=1;
memset(ch[0],0,sizeof(ch[0]));
build();
for(int i=0;i<n;i++){
printf("%d ",cal(a[i]));
}
return 0;
}
E. Picking Strings
推一推幾個式子就可以發現:
B可以變成C,所以兩串中的C都當成B來看。
任何B之前可以新增任意數量的A,所以對於查詢區間非末尾的A都可以無視掉。
B的數量自能增加不能減少,且只能偶數倍的增加
區間末尾的A只能直接減少三個或者一個A變成兩個B或者兩個A變成兩個B。
所以統計一下B數量的字首和和A的字尾長度,然後分類討論一下就可以了。
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define MP make_pair
const int maxn=100005;
const int maxm=(1<<25);
int n,m;
char s[maxn],t[maxn];
int bn1[maxn],bn2[maxn];
int an1[maxn],an2[maxn];
int a,b,c,d;
int main(){
scanf("%s%s",s+1,t+1);
n=strlen(s+1),m=strlen(t+1);
for(int i=1;i<=n;i++){
bn1[i]+=bn1[i-1]+(s[i]!='A'?1:0);
if(s[i]!='A')continue;
an1[i]=1+an1[i-1];
}
for(int i=1;i<=m;i++){
bn2[i]+=bn2[i-1]+(t[i]!='A'?1:0);
if(t[i]!='A')continue;
an2[i]=1+an2[i-1];
}
int Q;
scanf("%d",&Q);
while(Q--){
scanf("%d%d%d%d",&a,&b,&c,&d);
int b1num=bn1[b]-bn1[a-1];
int a1num=min(b-a+1,an1[b]);
int b2num=bn2[d]-bn2[c-1];
int a2num=min(d-c+1,an2[d]);
if(b1num>b2num){putchar('0');continue;}
if(b1num==b2num){
if(a1num<a2num){putchar('0');continue;}
int cha=a1num-a2num;
if(cha%3){putchar('0');}
else putchar('1');
continue;
}
if(b1num==0){
if(b2num%2){putchar('0');continue;}
if(a1num<=a2num){putchar('0');continue;}
int lef=(a1num-a2num)%3;
if(lef>b2num){putchar('0');continue;}
putchar('1');
continue;
}
if(b1num<b2num){
int cha=b2num-b1num;
if(cha%2){putchar('0');continue;}
if(a1num<a2num){putchar('0');continue;}
int lef=(a1num-a2num)%3;
if(b1num+lef>b2num){putchar('0');continue;}
putchar('1');
continue;
}
}
return 0;
}