题目链接
D.Chat in a Circle
手玩一下发现,除了最大的数,其他的数最多能加两次。
#include
using namespace std;
typedef long long LL;
const int N = 2e5 + 10;
#define fi first
#define se second
#define pb push_back
#define wzh(x) cerr<<#x<<'='<
int n,a[N];
int main() {
ios::sync_with_stdio(false);
cin>>n;
for(int i=1;i<=n;i++)cin>>a[i];
sort(a+1,a+1+n,greater<int>());LL ans=a[1];
int f=n-2,l=2;
while(f>0){
ans+=a[l];
f--;if(!f)break;
ans+=a[l];f--;l++;
}
cout<<ans<<'\n';
return 0;
}
E - Multiplication 4
分类讨论。
1.先看<0,>0的数够不够k个,不够答案显然为0
2.看答案是否>0
----2.1如果答案>0,那么显然是选偶数个<0的,剩下全是>0的,如果k是奇数的话先拿一个>0最大的,然后贪心每次从>0,<0里面 拿两个乘积最大的。
3.答案<0的时候:那么显然贪心拿绝对值最小的。。。特判一下=0的情况
#include
using namespace std;
typedef long long LL;
const int N = 2e5 + 10;
#define fi first
#define se second
#define pb push_back
int n,k,a[N],dx[N],dy[N];
const LL mod=1e9+7;
LL px[N],py[N];
long double lg[N],gl[N];
int main() {
ios::sync_with_stdio(false);
cin>>n>>k;int x=0,y=0,z=0;
for(int i=1;i<=n;i++)cin>>a[i];
for(int i=1;i<=n;i++){
if(a[i]>0){
dx[++y]=a[i];
}else if(a[i]<0){
dy[++z]=a[i];
}else{
x++;
}
}
if(z+y<k)cout<<0<<'\n';
else{
sort(dx+1,dx+1+y,[](int x,int y){return x>y;});//++
sort(dy+1,dy+1+z);//--
int st=0;
for(int i=0;i<=min(z,k);i+=2){
if(k-i<=y)st=1;
}
if(!st){//必是负数
if(x)return cout<<0,0;
sort(dx+1,dx+1+y);
sort(dy+1,dy+1+z,greater<int>());
int dl=1,dr=1;
LL temp=1;
while(k){
if(dl<=y && dr<=z){
if(dx[dl]<abs(dy[dr])){
temp*=dx[dl];
temp%=mod;
dl++;
}else{
temp*=dy[dr];
temp%=mod;
dr++;
}
}else if(dl<=y){
temp*=dx[dl];
temp%=mod;
dl++;
}else{
temp*=dy[dr];
temp%=mod;
dr++;
}
k--;
}
cout<<(temp+mod)%mod;
}else{
sort(dx+1,dx+1+y,greater<int>());
sort(dy+1,dy+1+z);
LL temp=1;
int l=1,r=1;
if(k&1)temp*=dx[l++],temp%=mod,k--;
while(k){
if(y-l>=1 && z-r>=1){
if(1ll*dx[l]*dx[l+1]>=1ll*dy[r]*dy[r+1]){
temp*=dx[l];
temp%=mod;
temp*=dx[l+1];
temp%=mod;
l+=2;
k-=2;
}else{
temp*=dy[r];
temp%=mod;
temp*=dy[r+1];
temp%=mod;
r+=2;
k-=2;
}
}else if(y-l>=1){
temp*=dx[l];
temp%=mod;
temp*=dx[l+1];
temp%=mod;
l+=2;
k-=2;
}else if(z-r>=1){
temp*=dy[r];
temp%=mod;
temp*=dy[r+1];
temp%=mod;
r+=2;
k-=2;
}
}
cout<<(temp+mod)%mod<<'\n';
}
}
return 0;
}
F - Intervals on Tree
树的 顶点数=边数+1
那么一个森林的 顶点数=边数+联通块数量
f ( L , R ) f(L,R) f(L,R)代表的一个点集构成的必然是一个森林,联通快数量=R-L+1 - 边数
顶点的总和可以很容易计算,那么我们去掉边数,对每个边单独考虑,计算每个边被多少个点集包括即可。
#include
using namespace std;
typedef long long LL;
const int N = 2e5 + 10;
#define fi first
#define se second
#define pb push_back
#define debug(x) cerr<<"x ="<
int n;
int main() {
ios::sync_with_stdio(false);
cin>>n;LL ret=0;
for(int i=1;i<=n;i++){
ret+=1ll*(n-i+2)*(n-i+1)/2;
}
// debug(ret);
for(int i=1;i<n;i++){
int s,t;
cin>>s>>t;
if(s>t)swap(s,t);
ret-=1ll*s*(n-t+1);
}
cout<<ret<<'\n';
return 0;
}