题意:给你一串非负整数,可以将一个非零数减1,加到相邻的数字上,要使其中所有最大数字的和最小。
题解:模拟可以过。也可以分析,可以要减少最大数字和,如果最大数字出现大于等于3次,可以把最大数字加一,或者把某个最大数字减一,最大数字出现减少一次。但是要注意一些特殊情况,下面详述。
先扫一遍,如果最大数字为0,那么输出0,如果最大数字为1,那么如果可以合并成2的话,那么就输出2,否则输出数字和sum。否则,看最大数字出现次数,如果为一次,那么检查,周围是否有比它小3的数字,(如果只是比它小2的话,那么操作完以后至少会出现两个次大的数字),如果有还有检查一下操作前是否有次大的数字,然后根据检查情况输出Max或Max-1;如果出现两次,检查两个最大数字周围有没有比它小2的数字,如果有输出Max,没有的话输出Max+1,(Max>=2且不满足前者,周围一定有数字非零);对于次数大于等于3次的,检查最大数字周围有没有非零数字,如果有输出Max+1,否则sum-Max。
#include<cstdio> #include<cmath> #include<vector> #include<map> #include<set> #include<algorithm> using namespace std; //#define local typedef long long ll; const int maxn = 1e5+5; int p[maxn]; int main() { #ifdef local freopen("in.txt","r",stdin); //freopen("out.txt","w",stdout); #endif // local int n; scanf("%d",&n); ll Max = 0; int pos = -1; for(int i = 0; i < n ;i++){ scanf("%d",p+i); if(p[i]>Max){ Max = p[i];pos = i; } } if(Max == 0){ printf("0"); return 0;} if(Max == 1){ int sum = p[0]; bool canMerge = false; for(int i = 1; i < n; i++){ sum += p[i]; if(p[i]&&p[i-1]) { canMerge = true; break; } } if(canMerge) printf("2"); else printf("%d",sum); return 0; } long long sum = 0; bool canMerge = false; bool lessone = false; for(int i = pos; i < n; i++){ if(p[i] == Max) sum += Max; } if(sum == Max){ if(pos>0) { if(p[pos-1]<=p[pos]-3)lessone = true; } if(pos<n-1) { if(p[pos+1]<=p[pos]-3)lessone = true; } if(lessone) { for(int i = 0; i < n; i++){ if(p[i] == Max-1) { printf("%d",Max); return 0; } } printf("%d",Max-1); } else printf("%d",Max); return 0; } if(sum == Max*2){ //keng for(int i = pos; i < n; i++){ if(p[i] == Max){ if((i>0&& p[i-1]<= Max-2 )|| (i<n-1&& p[i+1] <= Max-2 ) ){ printf("%d",Max); return 0; } } } printf("%d",Max+1); } for(int i = pos; i < n; i++){ if(p[i] == Max){ if((i>0&& p[i-1])|| (i<n-1&& p[i+1] ) ) { printf("%d",Max+1); return 0; } } } printf("%I64d",sum-Max); return 0; }