您的位置:首页 > 其它

陕西省集训day1(枚举,贪心,二分)

2016-08-20 09:48 513 查看
http://acm.hust.edu.cn/vjudge/contest/125415#overview

整场比赛的链接QAQ

A题:

http://codeforces.com/problemset/problem/478/C

题意:

告诉你三种颜色的气球各几个,每张桌子需要3个气球,每张桌子上的三个气球颜色不能完全一样,问用已知的气球最多摆几只桌子

思路:

第一反应一定是相加除以三,但是有可能多的那个有剩余。

从小到大排序,如果最少的和第二少的都分开,分别放在不同的桌子上,那么最多的那个颜色比这个都多就说明多的部分是没有用处的=。=

#include <iostream>
#include <cstdio>
#include <algorithm>
using namespace std;

int main()
{
long long a[4];
long long sum = 0;
for(int i = 0 ; i < 3 ; i++)
cin >> a[i];

sort(a,a+3);
a[2] = min(a[2],(a[0]+a[1])*2 );
for(int i = 0 ; i < 3 ; i++)
sum += a[i];
long long k = sum/3;
cout << k << endl;
return 0;
}


B题:

http://codeforces.com/problemset/problem/456/A

有点智障QAQ,直接给代码

#include <iostream>
#include <cstdio>
#include <algorithm>

using namespace std;
struct node
{
int p,q;
}a[100010];

bool cmp(node c,node b)
{
if(c.p != b.p)
return c.p <b.p;
return c.q < b.q;
}

int main()
{
int n;
cin >> n;
for(int i = 0 ; i  < n ;i++)
scanf("%d%d",&a[i].p,&a[i].q);
sort(a,a+n,cmp);
int i;
for( i =1; i < n ;i++)
if(a[i].q < a[i-1].q)
break;
if(i == n)
cout << "Poor Alex"<<endl;
else
cout << "Happy Alex"<<endl;
return 0;

}


C题:

http://codeforces.com/problemset/problem/460/B

题意:

给你a,b,c,求多少个n满足使得x = b·s(x)a + c,成立 其中(s(x) = x各个位置上数字之和)

思路:

首先a,b,c都确定的情况下,枚举各个x一定可以知道符合条件的,但是由于x的范围实在是太大了,所以换个思路,x最大是999999999,但是s(x)最大就是81,那么显然我们可以转变思路枚举s(x)。

#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
int ans[100010];

int work(int x)     //求出当前x真正的s(x),检查与之前的是否一致
{
int an = 0;
while(x)
{
an += x%10;
x /= 10;
}
//  cout << an <<endl;
return an;
}

int main()
{
long long a,b,c;
cin>>a>>b>>c;
int cnt = 0;
for(int i = 1 ; i <= 81;i++) //枚举s(x)
{
long long x = 1;
for(int j = 0 ; j < a;j++)
x *= i;
x = b*x +c;
if(x <0 || x>1e9)
continue;
if(work(x) == i)
ans[cnt++] = x;
}
cout << cnt <<endl;
for(int i = 0 ; i < cnt ;i++)
printf("%d%c",ans[i],(i == cnt-1)?'\n':' ');

return 0;
}


D题:

http://codeforces.com/problemset/problem/462/B

题意:

共有N张牌,从中选出K张,得分为每次选出牌的面值与选该牌的数量。求最大得分。

思路:

贪心,尽可能取数量最多的牌,大于k的时候取到k

统计的时候,因为都是字母,直接再开一个数组统计到字母所在的位置对应下标即可。

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
char s[100010];
long long a[30];

bool cmp(int a,int b)
{
return a>b;
}
int main()
{
long long n,k;
cin >> n >> k;
scanf("%s",s);
for(int i = 0 ; i< n;i++)
a[s[i]-'A'] ++;
sort(a,a+26,cmp);
long long ans = 0;
for(int i = 0 ; i < 26;i++)
{
if(k >= a[i])
k -= a[i],ans += a[i]*a[i];
else
{
ans += k * k;
break;
}
if(k == 0)
break;
}

cout << ans <<endl;
return 0;
}


E题:

http://codeforces.com/problemset/problem/446/B

题意:

给你一个n*m的矩阵,做k次操作,每次在一行或者一列每个数上减p,每次操作的欢乐值是减之前该行或者该列数字之和,问欢乐值最大是多少

思路:

显然是一道贪心,一定要先把最大的加上去,尽量不要出现负数

对行的操作和对列的操作可以看做相互独立的,最后知道了减了多少行减了多少列,就可以算出公共的减了多少个数字,在单独减下去就好,最后枚举k个中多少个是行,多少个是列,求出最大的就好啦,这个思路不是很好想=。=,也是今天最难的一道题了把。(优先队列默认从大到小排序,这就一点都不费事了)

#include <iostream>
#include <cstdio>
#include <cstring>
#include <queue>
using namespace std;
long long col[1010],row[1010],a,rr[1000010],cc[1000010];
priority_queue<long long>qr,qc;
int main()
{
long long n,m,k,p;
cin >>n >>m >>k >>p;
for(int i = 0 ; i < n ;i++)
for(int j = 0 ; j < m ;j++)
{
scanf("%I64d",&a);
col[j] += a;
row[i] += a;
}
for(int i = 0 ; i < n ;i++)
qr.push(row[i]);
for(int i = 0  ; i < m ; i++)
qc.push(col[i]);
for(int i = 1 ; i <= k ;i++)
{
long long pr = qr.top();
//cout <<pr <<endl;
qr.pop();
rr[i] = rr[i-1]+pr;
pr -=p*m;    //同一行可以再用,所以一定记得放进去再
qr.push(pr);
}

for(int i = 1 ; i <= k ;i++)
{
long long pc = qc.top();
//  cout << pc <<endl;
qc.pop();
cc[i] = cc[i-1]+pc;
pc -= p*n;
qc.push(pc);
}

long long ans = rr[0]+cc[k];
for(int i = 1; i <= k ;i++)
ans = max(ans,rr[i]+cc[k-i]-(i*p*(k-i)));
cout << ans <<endl;
return 0;
}


F题:

http://codeforces.com/problemset/problem/451/B

题意:

给定一个序列,最后要求他变成升序,但是操作只能是一次区间反转。

思路:

遇到该反转的地方就标记一下,不需要的地方停止,如果后面又出现了该反转的地方,自然就不符合题目的条件了。

#include <bits/stdc++.h>
using namespace std;
int a[100010];
int main()
{
int n;
cin >> n;

int l=0;
int r=0;
int c=0;
bool f=false;
cin  >> a[0];
for(int i=1; i<n; i++)
{
cin >> a[i];
if(a[i]<a[i-1] && !f)
{
l = i-1;
f=true;
c++;
}
if(i && a[i]>a[i-1] && f)
{
f=false;
r=i-1;
}
}
if(f)
r=n-1;

if(c>1 || r<n-1 && a[r+1]<a[l] || l>0 && a[l-1] > a[r])
{
cout << "no";
}
else
{
cout << "yes" << endl;
cout << l+1 << ' ' << r+1;
}
return 0;
}


G题:

http://codeforces.com/problemset/problem/490/E

题意:

问号处加上数字,使得这几行成单调递增

思路:

首先处理第一行,首位如果是?那直接给1(每一行都是这样),其他位置是?的直接给0,如果不是第一行,那么其他位置是?的情况就要分两种,一种是上一行比这一行长度短,那么没啥说的直接给0,如果一样长,比较前面的部分,如果前面已经比上一行大了,直接给0,如果一样,给上一行当前列的数组+1,那么数字,如果上一行是9,那么显然做不到单调递增,于是只能输出no,后面的操作也可以随之停止了。

#include <cstdio>
#include <iostream>
#include <cstring>
using namespace std;
char s[100010][15];
bool cmp(char a[],char b[],int len)
{
for(int i=0;i<len;i++)
{
if(a[i]=='?'&&b[i]!='9')return true;
if(a[i]!='?'&&a[i]>b[i])return true;
if(a[i]!='?'&&a[i]<b[i])return false;
}
return false;
}
int len[100010];
int main()
{
int n;
scanf("%d",&n);
for(int i=0;i<n;i++)
scanf("%s",s[i]);
for(int i=0;i<n;i++)
len[i]=strlen(s[i]);
if(s[0][0]=='?')
s[0][0]='1';
for(int i=1;i<len[0];i++)
if(s[0][i]=='?')
s[0][i]='0';
for(int i=1;i<n;i++)
{
if(len[i]<len[i-1])
{
puts("NO");
return 0;
}
if(len[i]>len[i-1])
{
if(s[i][0]=='?')
s[i][0]='1';
for(int j=1;j<len[i];j++)
if(s[i][j]=='?')
s[i][j]='0';
}
else
{
if(s[i][0]=='?')
{
for(char ch='1';ch<='9';ch++)
{
s[i][0]=ch;
if(cmp(s[i],s[i-1],len[i]))
break;
}
}
for(int j=1;j<len[i];j++)
{
if(s[i][j]=='?')
{
for(char ch='0';ch<='9';ch++)
{
s[i][j]=ch;
if(cmp(s[i],s[i-1],len[i]))
break;
}
}
}
if(!cmp(s[i],s[i-1],len[i]))
{
puts("NO");
return 0;
}
}
}
puts("YES");
for(int i=0;i<n;i++)
puts(s[i]);
return 0;
}


H题:

http://codeforces.com/problemset/problem/500/C

题意:

一个人要读n本书每本书有个重量wi,每天读1本,一共m天。他每天把要看的书抽出来(把上面的搬开,拿出要读的书再把上面的书放回去,换言之,代价就是上面的书的重量和),看完以后放到一摞书的最上面,问根据他的阅读顺序怎样初始化书的排列顺序能使他搬书的重量最小,求出这个最小重量

思路:

按照看的顺序放书。

#include <cstdio>
#include <iostream>
#include <cstring>
using namespace std;
int w[510],b[1010],ans;
bool book[510];
int main()
{
int n,m;
cin >>n >>m;
for(int i = 1 ; i <=n; i++)
scanf("%d",&w[i]);
for(int j = 1 ; j <= m ; j++)
scanf("%d",&b[j]);
for(int i = 2; i<=m; i++)
{
memset(book,0,sizeof(book));
for(int j = i-1 ; j>0; j--)
{
if(b[j] == b[i])
break;
if(book[b[j]] == 0)
{
book[b[j]] = 1;
ans += w[b[j]];
}
}
}
cout <<ans<<endl;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: