A. Water Buying
题意:给q个询问,每个询问给出3个数字,n,a,b,a是买一升水的花费,b是买2升水的花费,求买n升水的最小花费。
思路:对于每个询问,我们比较2*a和b的大小,如果2*a比b小的话就一直买1升水就行了,否则若n是偶数,全买2升水,若n是奇数,先买一桶一升水的,剩下的全买两升水的,事实上题目里面没有规定a一定比b小,但数据里面似乎是这样的,更严谨的话就应该判断a是否大于b然后看是一升水的要不要买。
代码:
#include<bits/stdc++.h>
using namespace std;
#define inf 0x3f3f3f3f
#define ll long long
const int maxn=1e3+9;
//int a[maxn],b[maxn];
int main(){
int i,j,k,n,t;
cin>>t;
for(i=1;i<=t;i++){
ll n,a,b;
cin>>n>>a>>b;
if(a*2<=b){
ll ans=a*n;
cout<<ans<<endl;
}
else{
ll ans=(n/2)*b+(n-n/2*2)*a;
cout<<ans<<endl;
}
}
}
B. Tanya and Candies
题意:先删去序列里的一个数,然后看奇数位置的数之和是否和偶数位置的数之和相等,若相等,这个删去的数是好的,问有几个这样的good数
思路:统计每个位置偶数位置的数的前缀和,奇数位置的前缀和,很容易能够发现删去一个数之后,这个数之后的数的位置,奇变偶,偶变奇,那么此时偶数位置的数之和就等于eve[i-1]+odd[n]-odd[i],奇数位置的数之和就等于odd[i-1]+eve[n]-eve[i],我们判断他们是否相等就行了
代码:
#include<bits/stdc++.h>
using namespace std;
#define inf 0x3f3f3f3f
#define ll long long
const int maxn=2e5+9;
ll a[maxn],odd[maxn],eve[maxn];
int main(){
int i,j,k,n;
cin>>n;
for(i=1;i<=n;i++){
cin>>a[i];
if(i%2==1){
eve[i]=eve[i-1];
odd[i]=odd[i-1]+a[i];
}
else{
odd[i]=odd[i-1];
eve[i]=eve[i-1]+a[i];
}
}
ll ans=0;
for(i=1;i<=n;i++){
int ODD=0,EVE=0;
ODD=odd[i-1]+eve[n]-eve[i];
EVE=eve[i-1]+odd[n]-odd[i];
if(ODD==EVE){
ans++;
}
}
cout<<ans<<endl;
}
C. Palindromic Matrix
题意:给你n*n个数,让你构造一个矩阵,这个矩阵左右对称,上下对称
思路:对于n是偶数的情况,我们能够发现每个数出现的次数必须是4的倍数才能构造这样的矩阵,我们开个map储存一下每个数出现的次数,只用处理左上角那四分之一部分,其余的对称就行了,对于这一部分的每个位置,遍历所有出现过的数,如果mp[x]>=4,把x放在这个位置,然后mp[x]-=4;然后n是奇数的情况,中间一行和中间一列的数mp[x]>=2就行了(最中间位置的数出现次数大于等于1就行),然后也是类似的解决方法。
代码:
#include<bits/stdc++.h>
using namespace std;
#define inf 0x3f3f3f3f
#define ll long long
const int maxn=1e3+9;
int a[maxn],p[maxn][maxn];
map<long long ,int>mp;
int main(){
int i,j,k,n;
cin>>n;
for(i=1;i<=n*n;i++){
cin>>a[i];
mp[a[i]]++;
}
int _1cnt=0,_2cnt=0;
for(auto it:mp){
int x=it.second;
if(n%2==0){
if(x%4!=0){
cout<<"NO"<<endl;
return 0;
}
}
else{
if(x%4!=0){
if(x%2==0){
_2cnt++;
}
else if(x%2==1){
_1cnt++;
}
if(_1cnt>1||_2cnt>(n/2)*2){
cout<<"NO"<<endl;
return 0;
}
}
}
}
cout<<"YES"<<endl;
if(n%2==0){
for(i=1;i<=n/2;i++){
for(j=1;j<=n/2;j++){
for(auto it:mp){
int x=it.second,y=it.first;
if(x>=4&&x%4==0){//cout<<y<<endl;
p[i][j]=y;
mp[y]-=4;
break;
}
}
p[i][n-j+1]=p[i][j];
p[n-i+1][j]=p[i][j];
p[n-i+1][n-j+1]=p[i][j];
}
}
}
else{
for(auto it:mp){
int x=it.second;
if(x%2)p[n/2+1][n/2+1]=it.first;
}
for(i=1;i<=n/2;i++){
for(j=1;j<=n/2;j++){
for(auto it:mp){
int x=it.second,y=it.first;
if(x>=4){
p[i][j]=y;
mp[y]-=4;
break;
}
}
p[i][n-j+1]=p[i][j];
p[n-i+1][j]=p[i][j];
p[n-i+1][n-j+1]=p[i][j];
}
}
for(i=1;i<=n/2;i++){
if(i==n/2+1)continue;
for(auto it:mp){
int x=it.second,y=it.first;
if(x>=2){
p[i][n/2+1]=y;
mp[y]-=2;
// cout<<mp[y]<<"sfsaf"<<y<<endl;
break;
}
}
p[n-i+1][n/2+1]=p[i][n/2+1];
}
for(j=1;j<=n/2;j++){
if(j==n/2+1)continue;
for(auto it:mp){
int x=it.second,y=it.first;
if(x>=2){
// cout<<123<<endl;
p[n/2+1][j]=y;
mp[y]-=2;
break;
}
}
p[n/2+1][n-j+1]=p[n/2+1][j];
}
}
for(i=1;i<=n;i++){
for(j=1;j<=n;j++){
cout<<p[i][j]<<' ';
}
cout<<endl;
}
}
D1. Coffee and Coursework (Easy version)
题意:给你n杯咖啡和你需要完成的作业的页数m,如果一杯咖啡是一天中的第一杯,那么可以写ai页,如果是第二杯,可以写max(0,ai-1)页,第三杯可以写max(0,ai-2)页.......,问最少需要几天可以把作业写完
思路:先对咖啡从大到小排序,然后枚举天数,按题意暴力相加,看值的和是否大于等于m,如果是的话,就更新答案。
代码:
#include<bits/stdc++.h>
using namespace std;
#define inf 0x3f3f3f3f
#define ll long long
const int maxn=1e2+9;
int a[maxn];
bool cmp(int a,int b){
return a>b;
}
int main(){
int i,j,k,n,m;
cin>>n>>m;
int sum=0;
for(i=1;i<=n;i++){
cin>>a[i];
sum+=a[i];
}
if(sum<m){
cout<<-1<<endl;
return 0;
}
else{
int ans=inf;
for(k=n;k>=1;k--){
sum=0;
sort(a+1,a+n+1,cmp);
for(i=1;i<=k;i++){
sum+=a[i];
}
for(i=k+1;i<=n;i++){
sum+=max(0,a[i]-(i-1)/(k));
}
if(sum>=m){
//cout<<sum<<"sfsf"<<k<<endl;
ans=min(ans,k);
}
}
cout<<ans<<endl;
}
}
D2. Coffee and Coursework (Hard Version)
题意:这道题和D1的题意是一样的,就是数据范围不一样
思路:大致思路一样,不过由于数据范围增大,我们需要通过二分找完成作业的天数。
代码:
#include<bits/stdc++.h>
using namespace std;
#define inf 0x3f3f3f3f
#define ll long long
const int maxn=2e5+9;
ll a[maxn],n;
bool cmp(int a,int b){
return a>b;
}
ll solve(int k){
ll sum=0;
for(ll i=1;i<=k;i++){
sum+=a[i];
}
for(ll i=k+1;i<=n;i++){
sum+=max((long long)0,a[i]-(i-1)/(k));
}
return sum;
}
int main(){
ll i,j,k,m;
cin>>n>>m;
ll sum=0;
for(i=1;i<=n;i++){
cin>>a[i];
sum+=a[i];
}
if(sum<m){
cout<<-1<<endl;
return 0;
}
else{
ll ans=1e18;
sort(a+1,a+n+1,cmp);
ll l=1,r=n;
while(l<r){
int mid=(l+r)>>1;
if(solve(mid)>=m){
r=mid;
}
else{
l=mid+1;
}
}
// cout<<solve(4)<<"sfs"<<endl;
cout<<r<<endl;
}
E. Yet Another Ball Problem
题意:略
思路:构成成回文的形式就行了,最多有k*(k-1)对。
F1. Tree Cutting (Easy Version)
题意:给你一颗n个点的树,一些点是红色的,一些点是蓝色的,还要一些点是无色的,要你找出有多少条边拆去之后形成的两颗树,一颗树只存在红色点和无色点,一棵树只存在蓝色点和无色点。
思路:用dfs遍历整棵树,如果一个节点形成的子树包含所有的红色节点并且没有蓝色节点,则ans++。
代码:
#include<bits/stdc++.h>
using namespace std;
#define inf 0x3f3f3f3f
const int maxn=3e5+9;
int a[maxn],ans=0,r_ct=0,b_ct=0,_rd[maxn],_bl[maxn];
vector<int>vec[maxn];
void dfs(int v,int pre){
if(a[v]==1)_rd[v]++;
if(a[v]==2)_bl[v]++;
for(int i=0;i<vec[v].size();i++){
int u=vec[v][i];
if(u==pre)continue;
dfs(u,v);
_rd[v]+=_rd[u];
_bl[v]+=_bl[u];
}
if((_rd[v]==r_ct&&_bl[v]==0)||(_bl[v]==b_ct&&_rd[v]==0))ans++;
}
int main(){
ios::sync_with_stdio(0);
cin.tie(0);
int i,j,k,n;
cin>>n;
for(i=1;i<=n;i++){
cin>>a[i];
if(a[i]==1)r_ct++;
if(a[i]==2)b_ct++;
}
for(i=1;i<n;i++){
int x,y;
cin>>x>>y;
vec[x].push_back(y);
vec[y].push_back(x);
}
dfs(1,0);
cout<<ans<<endl;
}