题目链接:http://codeforces.com/contest/701
感想:以前打CF时,老是卡题,最后都很失败。这次虽然也卡了好多次,但是相对于以前来说,已经好多了。今天第一次做出第三题,虽然并不是很了不起,但是对自己来说是一个进步,好开森。要多多练习,更快速的解题,今天的前三道题,对自己来说,本来可以在45分钟之内就完成的,但最后还是花了一个多小时,以后要更快速地解决问题,加油。
A.思路:因为每个人手里的卡片值和最后要相等,并且保证有解且卡片数为偶数,所以最后每个人手里的卡片值和必为总值除以人数,即为平均数,然后从头到尾一一枚举,如果当前数没被访问,就从它后面再找一个没被访问的数,使得它们的和为平均数,输出答案并标记它们已被访问即可。
AC代码:
#include <bits/stdc++.h>
using namespace std;
const int maxn = 105;
int num[maxn];
bool vis[maxn];
int n;
int main(){
ios::sync_with_stdio(false);
cin.tie(0);
cin >> n;
int sum = 0;
for (int i=0; i<n; ++i){
cin >> num[i];
sum += num[i];
}
sum /= (n/2);
for (int i=0; i<n; ++i)
if (!vis[i]){
vis[i] = true;
for (int j=i+1; j<n; ++j)
if (!vis[j] && num[i]+num[j]==sum){
cout << i+1 << " " << j+1 << endl;
vis[j] = true;
break;
}
}
return 0;
}
B.思路:只要当前一个旗子放在某一个位置,这个位置所在行列都会被攻击,那么只要统计那些行列被占据了即可。所以用两个集合维护行列被占据了几行几列(集合可以避免重复),假设行占据了x行,列占据了y列,那么当前还剩下n*n-x*n-(n-x)*y个位置,输出这个值即可。
AC代码:
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
int n, m;
set<int> s1, s2;
int main(){
ios::sync_with_stdio(false);
cin.tie(0);
cin >> n >> m;
ll t = 1ll*n*n;
int a, b, c=0;
while (m--){
cin >> a >> b;
s1.insert(a);
s2.insert(b);
ll ans = t-1ll*s1.size()*n-1ll*(n-s1.size())*s2.size();
if (c)
cout << " ";
cout << ans;
++c;
}
cout << endl;
return 0;
}
C.思路:先找到最后一个才开始计数的位置,假设为r,那么答案最可能的就是r+1。但是再想想看,如果最左边的种类计数大于1,那么就说明在当前区间中,去掉最左边的种类之后,对所有种类在该区间没影响,这样就可以一直缩短区间,结束后更新答案。是不是这就是解了呢?当然不是,因为右边还没有访问完的话,将区间向右移一个位置,这样这个区间里的该种类计数又多了1,那么接着执行上面的过程可能会使得区间更短而且满足条件,因此就这样每次移一个位置,直到不能移动为止,执行上面的过程,更新答案,最后的答案一定是最好的。
AC代码:
#include <bits/stdc++.h>
using namespace std;
int n;
string str;
map<char, int> m;
int main(){
ios::sync_with_stdio(false);
cin.tie(0);
cin >> n >> str;
int l=0, r=0;
for (int i=0; i<n; ++i){
if (m[str[i]] == 0)
r = i;
++m[str[i]];
}
for (int i=r; i<n; ++i)
--m[str[i]];
int ans = r-l+1;
//cout << ans << endl;
--r;
while (++r < n){
++m[str[r]];
while (m[str[l]] > 1){
--m[str[l]];
++l;
}
ans = min(ans, r-l+1);
//cout << ans << endl;
}
cout << ans << endl;
return 0;
}