A
题意:给出n朵花的值ai, 然后给出m个区间, 你可以选一些区间, 现在规定每一朵花有一个美丽值, 第i朵话的美丽值 = ai * (ai在你所选出的区间中出现了几次), 求所有花美丽值的和的最大值.
思路:如果你选择了一个区间, 那么这个区间对答案的贡献就等于 区间所有数的和(很好理解, 因为每一朵花的美丽值是ai * 它出现的次数, 选择一个区间它自身的贡献就有一次, 一个区间的话就是整个区间的和了). 很显然, 如果和为正数, 则这个区间可以选, 负数则不选. 那么做一个和的前缀即可. sum[i] 代表 1~i 区间的和
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cmath>
#include <cctype>
#include <iostream>
#include <sstream>
#include <algorithm>
#include <set>
#include <queue>
#include <stack>
#include <deque>
#include <map>
#include <string>
#include <vector>
using namespace std;
const int qq = 1e5 + 10;
typedef long long ll;
ll num[qq];
ll sum[qq];
ll n, m, k;
int main(){
cin >> n >> m;
sum[0] = 0;
for(int i = 1; i <= n; ++i){
cin >> sum[i];
sum[i] += sum[i-1];
}
ll ans = 0;
for(int i = 0; i < m; ++i){
ll a, b; cin >> a >> b;
if((sum[b]-sum[a-1]) > 0) ans += (sum[b]-sum[a-1]);
}
cout << ans << endl;
return 0;
}
B
题意:有n(编号1~n)个袜子, k种颜色(编号1~k), m天, 给出每天穿的袜子的编号l, r, 问至少修改多少次可以使得每天穿的袜子都是相同颜色的.
思路:对每天穿的袜子进行并查集分块, 每一块的颜色值都是互不相同的, 因为如果某一个联通块中存在一个颜色与另外一个联通块中某个颜色一样, 那么说明他们是一个联通块, 那么每一个联通块对答案的贡献就是 联通块中的顶点个数 - 联通块中颜色最多的顶点个数. 并查集分块,用vector来存每一个联通块, 然后用map去计数每个联通块中的颜色.
#include<cmath>
#include<cstring>
#include<algorithm>
#include<cstdio>
#include<queue>
#include<string>
#include<stack>
#include<utility>
#include<vector>
#include<map>
using namespace std;
const int qq = 2e5+10;
int color[qq];
int pre[qq];
vector<int>v[qq];
int find(int x){
return pre[x]==x?x:pre[x]=find(pre[x]);
}
int main(){
int n,m,k;scanf("%d%d%d", &n, &m, &k);
for(int i=1; i<=n; ++i) scanf("%d", color+i);
for(int i=0; i<=n; ++i) pre[i] = i;
int a,b;
for(int i=0; i<m; ++i){
scanf("%d%d", &a, &b);
if(a>b) swap(a, b);
int x=find(a), y=find(b);
if(x!=y)
pre[y]=x;
}
// for(int i=1; i<=n; ++i)
// printf("%d\n", pre[i]);
for(int i=1; i<=n; ++i)
v[find(i)].push_back(i);
int sum=0;
map<int, int>Q;
for(int i=1; i<=n; ++i){
if(v[i].size()==0) continue;
//printf("%d\n", i);
for(int j=0; j<v[i].size(); ++j)
Q[color[v[i][j]]]++;
int maxn = 0;
for(map<int, int>::iterator it=Q.begin(); it!=Q.end(); ++it){
if((*it).second>maxn) maxn = (*it).second;
}
Q.clear();
sum = sum + (v[i].size() - maxn);
}
printf("%d\n", sum);
return 0;
}
C
一个基础搜索
#include<cmath>
#include<cstring>
#include<cstdio>
#include<string>
const int qq=15;
int n,k,sum;
char map[qq][qq];
int row[qq],col[qq];
void dfs(int x,int cnt)
{
if(cnt>=k){
sum++;
return;
}
for(int j,i=x;i<n;++i){
for(j=0;j<n;++j)
if(map[i][j]=='#'&&!row[i]&&!col[j]){
row[i]=col[j]=1;
dfs(i+1,cnt+1);
row[i]=col[j]=0;
}
}
}
int main()
{
while(~scanf("%d%d",&n,&k)){
if(n==-1&&k==-1) break;
for(int i=0;i<n;++i)
scanf("%s",map[i]);
memset(row,0,sizeof(row));
memset(col,0,sizeof(col));
sum=0;
dfs(0,0);
printf("%d\n",sum);
}
return 0;
}
E
题意:有n个字符, 每个字符有ai个, 用这些字符组成回文串, 求所有回文串中长度最小的, 要使的这个最小值最大.
思路: 有一个奇数个的字符 就会多一个回文串, 然后使得所有回文串尽量平均, 就是答案
#include<cmath>
#include<cstring>
#include<cstdio>
#include<queue>
#include<algorithm>
using namespace std;
const int qq=1e5+5;
int num[qq];
int main()
{
int t;scanf("%d",&t);
while(t--){
int n;scanf("%d",&n);
int odd=0,sum=0;
for(int i=0; i<n; ++i){
scanf("%d",&num[i]);
if(num[i]%2!=0) odd++;
sum+=num[i];
}
if(odd<=1) printf("%d\n",sum);
else{
if((sum/odd)%2!=0) printf("%d\n",sum/odd);
else printf("%d\n",sum/odd-1);
}
}
return 0;
}