A. Vova and Train
题意:
找1~L之间 v 的倍数的个数,在区间[l,r]之间的不能算。
题解:
简单的公式题。
代码:
#include<algorithm>
#include<iostream>
#include<cstdio>
#include<cmath>
using namespace std;
typedef long long ll;
int main()
{
ll L,v,l,r;
int t;
cin>>t;
while(t--)
{
cin>>L>>v>>l>>r;
ll ans = L/v;
ll a = (l-1)/v;
ll b = r/v;
cout<<ans-(b-a)<<endl;
}
return 0;
}
B. Heaters
题意:
在数列中值为1的位置有1个加热器,它能覆盖它的左边第 r-1 位置到它的右边 r-1 的位置,问最少多少个加热器能覆盖整个区间。
题解:
贪心,每次从一个加热器能覆盖区间的中心开始贪,这样保证最优。
代码:
#include<algorithm>
#include<iostream>
#include<cstdio>
#include<cmath>
using namespace std;
typedef long long ll;
int a[1999];
int main()
{
int n,r;
cin>>n>>r;
for(int i=1; i<=n; i++)
cin>>a[i];
int ans = 0;
int per = 0;
if(n<=r) //只要有一个位置是加热器就能覆盖整个区间
{
for(int i=1;i<=n;i++)
{
if(a[i])
{
cout<<1;
return 0;
}
}
cout<<-1;
return 0;
}
for(int i=r; i<=n;) //第一次的覆盖中心位置是r
{
if(a[i])
{
ans++;
per = i;
i = i+2*r-1; //移到下一个覆盖中心位置
}
else //往回找到一个加热器
{
bool vis =false;
for(int j=i-1; j>per; j--)
{
if(a[j])
{
ans++;
per = j;
i=j+2*r-1;
vis = true;
break;
}
}
if(!vis) //找不到的话,那么per+r这个位置肯定是不能被覆盖了
{
cout<<-1;
return 0;
}
}
}
if(per+r>n)
{
cout<<ans;
return 0;
}
bool tig = false;
for(int i=n; i>n-r; i--)//只有n-r以上的点才能覆盖n点
{
if(a[i])
{
ans++;
tig = true;
break;
}
}
if(tig) cout<<ans;
else cout<<-1;
return 0;
}
C. Books Queries
题意:
三种操作:
L id ,将编号为id的书放在最左边;
R id,将编号为id的书放在最右边;
?id,查询编号为id的书左右两边哪一边的数量最小,输出最小值。
题解:
编号并不是很大,可以开一个数组记录id所在的位置,再记录已有书的最左最右的位置。
代码:
#include<iostream>
#include<cstdio>
using namespace std;
const int maxn = 2e5+55;
int ans[2*maxn];
int main()
{
int q,index;
char s[10];
cin>>q;
int l=maxn;
int r=maxn+1;
while(q--)
{
scanf("%s%d",s,&index);
if(s[0]=='L')
{
ans[index]=l;
l--;
}
else if(s[0]=='R')
{
ans[index] = r;
r++;
}
else cout<<min(ans[index]-l-1,r-ans[index]-1)<<endl;
}
return 0;
}
D. Boxes Packing
题意:
有m个箱子,每个箱子容量为k,问你最多能装多少个物品,你只能依次舍弃前面的,后面的必须全部装完。
题解:
从后面依次开始来装箱子就符合题意了。
代码:
#include<iostream>
#include<cstdio>
using namespace std;
const int maxn = 2e5+55;
typedef long long ll;
int a[maxn];
int main()
{
int n,m,k;
while(cin>>n>>m>>k)
{
for(int i=0;i<n;i++)
scanf("%d",&a[i]);
int ans = 0;
int val = k;
m--;
for(int i=n-1;i>=0;i--)
{
if(val>=a[i])
{
val-=a[i];
ans++;
}
else if(m&&k>=a[i])
{
val = k-a[i];
ans++;
m--;
}
else break;
}
cout<<ans<<endl;
}
return 0;
}
E. Binary Numbers AND Sum
题意:
看样例解释就明白了。
题解:
依次模拟铁定要超时,b串中的1要和a串中相同位置后的所有1都会有一个&值,比如:a:1011,b:1001;b串第一个1和a串中的三个1都会有一个&值,分别是2^3、2^1、2^0,这些值的和就是b串第一个1对ans的贡献。快速幂处理下a串的后缀和就优化为O(nlogn)了。
代码:
#include<iostream>
#include<cstdio>
using namespace std;
const int maxn = 2e5+55;
typedef long long ll;
const int mod = 998244353;
char a[maxn],b[maxn];
ll ans[maxn];
ll Fast_pow(ll a,ll b)
{
ll ans=1,tep=a;
while(b){
if(b&1) ans=ans*tep%mod;
tep=tep*tep%mod;
b=b>>1;
}
return ans%mod;
}
int main()
{
int n,m;
cin>>n>>m;
scanf("%s %s",a,b);
int x = 0;
for(int i=n-1;i>=0;i--) //a串后缀和
{
if(a[i]=='0') ans[i] = ans[i+1];
else ans[i] = (Fast_pow(2,x)+ans[i+1])%mod;
x++;
}
ll sum= 0;
if(n<m) //分类讨论下
{
for(int i=0;i<m-n;i++)
{
if(b[i]=='1')
sum = (sum+ans[0])%mod;
}
for(int i=m-n;i<m;i++)
{
if(b[i]=='1')
sum = (sum+ans[i-(m-n)])%mod;
}
}
else
{
for(int i=0;i<m;i++)
{
if(b[i]=='1')
sum = (sum+ans[i+(n-m)])%mod;
}
}
cout<<sum<<endl;
return 0;
}