PROBLEM B C D E F H I K ARE INCLUDED
Problem B. Billboard
题意:
有个公告板,大小为h*w,要贴n张公告,每个公告的长度是k,高度固定为1,公告放的要尽可能靠上并尽可能靠左,每给出一张公告,要求这个公告在满足要求的情况下放在了第几层。
思路:
按照线段树的做法的话,因为公告的高度固定为1,可以对公告板的高度进行切分,将其现在的宽度值存起来,然后每次遍历从左子树开始往下走,知道走到叶子节点满足要求即可。
代码:
#include <bits/stdc++.h>
using namespace std;
#define ls l,mid,rt*2
#define rs mid+1,r,rt*2+1
#define mi (l+r)>>1
const int MAXN=200000+100;
int n,m,k,tree[MAXN*4],v,pos,t;
void push_up(int rt){
tree[rt]=max(tree[rt*2+1],tree[rt*2]);
return ;
}
void query(int l,int r,int rt){
if(tree[rt]<v||pos!=-1) return ;
if(l==r){
tree[rt]-=v;
pos=l;
return ;
}
int mid=mi;
query(ls);
query(rs);
push_up(rt);
return ;
}
int main(){
freopen("billboard.in","r",stdin);
freopen("billboard.out","w",stdout);
int n,m;
while(scanf("%d%d%d",&n,&m,&t)!=-1){
n=min(t,n);
for(int i=1;i<n*4;i++) tree[i]=m;
for(int i=0;i<t;i++){
pos=-1;
scanf("%d",&v);
if(v<=m) query(1,n,1);
printf("%d\n",pos);
}
}
}
Problem C. Class
题意:
k 个人,安排坐在一个 N * M 的教室里,问每一行和每一列中最小的人数最大是多少。
思路:
选一排一列横铺纵铺即可。
代码:
#include <bits/stdc++.h>
using namespace std;
int main()
{
freopen("class.in","r",stdin);
freopen("class.out","w",stdout);
int k,n,m,a[104][104];
while(cin>>k>>n>>m){
int minn=(k+1)/2;
memset(a,0,sizeof(a));
for(int i=1;i<=minn&&i<=n;i++)
a[i][1]='#',k--;
for(int i=2;i<=minn&&i<=m;i++)
a[1][i]='#',k--;
cout<<min(min(n,m),minn)<<endl;
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
if(a[i][j]=='#')
cout<<'#';
else{
if(k){
cout<<'#';
k--;
}else{
cout<<'.';
}
}
}
cout<<endl;
}
}
}
Problem D. Deposits
题意:
给出长度为 N 的 a 数列,和长度为 M 的 b 数列,b 数列中的一个数和 a 数列中的一个 b[i] 的倍数可以组成一对,问能组成多少对?
思路:
分别记录每个数在 a 中出现的次数和在 b 中出现的次数。遍历并统计每个在 b 中的数的倍数。考虑到数据的最大值,算法的计算次数最高大致在 2千万 次以下。
代码:
#include <bits/stdc++.h>
using namespace std;
const int MAXN=1e6+1000;
long long a[MAXN],n,m,b[MAXN],x,ans;
int main()
{
freopen("deposits.in","r",stdin);
freopen("deposits.out","w",stdout);
while(scanf("%d",&n)!=-1){
ans=0;
memset(a,0,sizeof(a));
memset(b,0,sizeof(b));
for(int i=0;i<n;i++)
scanf("%d",&x),
a[x]++;
scanf("%d",&m);
for(int i=0;i<m;i++){
scanf("%d",&x);
b[x]++;
}
for(int i=0;i<MAXN;i++){
if(b[i])
for(int j=1;j*i<MAXN;j++)
ans+=b[i]*a[i*j];
}
cout<<ans<<endl;
}
}
Problem E. Enchanted Mirror
题意:
给出 str1 ,str2 ,str3 ,str4.问是否可以通过操作改变 str1 和 str2 ,使得 str1 == str3 ,str2 == str4.
操作为:只允许交换 str1 的任意两个位置上的字符。
交换 str1 的 i 位置 和 j位置 时,str2 的 len - i + 1 位置 和 len - j + 1 位置也会交换。(例 len==4,str1==str2=="1234",交换 str1 的 '3' 和 '4' 时 str2 的 '1' 和 '2' 也同时交换)。
思路:
尝试交换后发现先交换和后交换某一位置并不影响能否满足题意,故先将 str1 匹配至 str3 ,再利用 str1 中相同字母间的交换调节好 str2 .
代码:
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
int main()
{
freopen("enchanted.in","r",stdin);
freopen("enchanted.out","w",stdout);
char s[4][110];
while(scanf("%s",s[0])==1){
for(int i=1;i<4;++i)
scanf("%s",s[i]);
int l=strlen(s[0]);
for(int i=0;i<l;++i){
if(s[0][i]!=s[2][i]){
for(int j=i+1;j<l;++j){
if(s[2][i]==s[0][j]){
swap(s[0][i],s[0][j]);
swap(s[1][l-i-1],s[1][l-j-1]);
break;
}
}
}
}
if(strcmp(s[0],s[2])==0)
{
for(int i=0;i<l;++i){
if(s[1][i]!=s[3][i]){
bool flag=0;
for(int j=i+1;j<l;++j){
if(s[3][i]==s[1][j]&&s[0][l-i-1]==s[0][l-j-1]){
swap(s[1][i],s[1][j]);
flag=1;
break;
}
}
if(!flag) break;
}
}
if(strcmp(s[1],s[3])==0)
puts("Yes");
else
puts("No");
}
else
puts("No");
}
return 0;
}
题意:
思路:
一个找规律的题,b[2]=a[2]要求a[1]=0,b[4]=a[4]要求a[2]+a[3]=0,b[6]=a[6]要求a[5]=0,b[8]=a[8]要求a[4]+a[6]+a[7]=0,到这里就可以看出来规律了,一个偶数可以对2^n取余为0,则要求他前面的n个数和为0,这个n个数的递减规律是1.1.2.4.8.16....2^n
代码:
#include <bits/stdc++.h>
using namespace std;
int main()
{
freopen("fenwick.in","r",stdin);
freopen("fenwick.out","w",stdout);
int t,n,flag;
long long a[100005],sum;
long long n2[16]={2,4,8,16,32,64,128,256,512,1024,2048,4096,8192,16384,32768,65536};
long long b[16]={1,1,2,4,8,16,32,64,128,256,512,1024,2048,4096,8192,16384};
while(cin>>n){
for(int i=1;i<=n;i++)
scanf("%lld",&a[i]);
for(int i=2;i<=n;i+=2){
sum=0;
flag=-1;
t=i;
for(int j=0;j<16;j++){
if(i%n2[j]==0)
flag=j;
else
break;
}
for(int j=0;j<flag;j++){
t-=b[j];
sum+=a[t];
}
t-=b[flag];
a[t]=-sum;
}
for(int i=1;i<=n;i++)
i==n?cout<<a[i]<<endl:cout<<a[i]<<" ";
}
return 0;
}
Problem H. Holes
题意:
输出一个最小的数,数字中有 N 个孔。不能有前导零。
思路:
N==0 时输出一个 0
否则奇数先输出一个 4 ,其他输出 8。
代码:
#include <bits/stdc++.h>
using namespace std;
int main(){
freopen("holes.in","r",stdin);
freopen("holes.out","w",stdout);
int n;
while(cin>>n){
if(n==0){
cout<<1<<endl;
}else if(n==1){
cout<<0<<endl;
}else{
if(n%2) cout<<4;
for(int i=1;i<=n/2;i++) cout<<8;
cout<<endl;
}
}
}
Problem I. Important Wires
题意:
六级阅读材料。给出 A B C........,几个表达式,输出一个包含 A B C.......且值为true的表达式。
思路:
请输出 A || B || C...........|| !A
代码:
#include <bits/stdc++.h>
using namespace std;
int n;
string str;
int main(){
freopen("important.in","r",stdin);
freopen("important.out","w",stdout);
while(cin>>n){
getchar();
cout<<"Yes"<<endl;
for(int i=0;i<n;i++){
getline(cin,str);
//cout<<str<<endl;
cout<<str[0]<<"|";
}
cout<<"~"<<str[0];
}
}
Problem K. Key to Success
题意:
给你n枚硬币,让你往里面添加m枚硬币,使得这n+m枚硬币,能组成1到x的所有的数,且x尽可能的大
思路:
我们就从头开始计数,首先必须要有一个1,然后我们就从头开始加,如果sum小于下一个数-1,那么这中间的数就拼不出来了,我们就要放一个sum+1上去,这样一直跑下去,放完为止。
我们可以多思考一下,类似于二进制,我们只要有了 1,2,4,8,16,32..........这些数我们就可以一直配下去,相当于每一个二进制位我们都可以配为 1 ,所以我们可以得到所有数。
代码:
#include <bits/stdc++.h>
using namespace std;
long long a[70],ans[70];
int main(){
freopen("key.in","r",stdin);
freopen("key.out","w",stdout);
int n,m,x;
while(cin>>n>>m){
memset(a,0,sizeof(a));
for(int i=1;i<=n;i++)
cin>>a[i];
long long sum;
for(int k=0;k<m;k++){
sum=0;
sort(a,a+n+k+1);
for(int i=0;i<=n+k;i++){
sum+=a[i];
if(sum+1<a[i+1]){
a[n+k+1]=sum+1;
ans[k]=sum+1;
break;
}
}
if(a[n+k+1]==0){
a[n+k+1]=sum+1;
ans[k]=sum+1;
}
}
for(int i=0;i<m;i++)
if(i) cout<<' '<<ans[i];
else cout<<ans[i];
cout<<endl;
}
}