传送门:A. Cards (暴力)
思路:因为每个人手里的卡片值和最后要相等,并且保证有解且卡片数为偶数,所以最后每个人手里的卡片值和必为总值除以人数,即为平均数,然后从头到尾暴力一下,如果当前数没被访问,就从它后面再找一个没被访问的数,使得它们的和为平均数,输出答案并标记它们已被访问即可。
#include <bits/stdc++.h>
using namespace std;
const int N = 105;
int num[N];
bool vis[N];
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;
}
另外一种做法,分给每个人的肯定一大一小配对的,所以先排序一下,用pair记住原来的位置即可(当时想的这个方法,但是并没有很好的用STL实现)
#include <bits/stdc++.h>
using namespace std;
int n;
vector<pair<int, int> > cards;
//-----------------------------------------------------------------
int main()
{
scanf("%d", &n);
for(int i=0; i<n; i++){
int a;
scanf("%d", &a);
cards.push_back(make_pair(a, i + 1));
}
sort(cards.begin(), cards.end());
for(int i=0; i<n/2; i++) {
int j = n-1-i;
printf("%d %d\n", cards[i].second, cards[j].second);
}
}
题意:~
思路:只要当前一个旗子放在某一个位置,这个位置所在行列都会被攻击,那么只要统计那些行列被占据了即可。所以用两个集合维护行列被占据了几行几列(集合可以避免重复),假设行占据了x行,列占据了y列,那么当前还剩下n*n-x*n-(n-x)*y个位置,输出这个值即可。当时刚刚做的时候还傻傻的用数组。。。
#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. They Are Everywhere (尺取法)
尺取法裸题,类似于POJ3320
#include <bits/stdc++.h>
#define ll __int64
using namespace std;
const int inf=0x3f3f3f3f;
int n;
char s[100005];
int a[100005];
void solve(){
set<int>all;
for(int i=0; i<n; i++){
all.insert(a[i]);
}
int len=all.size();
// printf("len=%d\n",len);
int s=0,t=0,num=0;
map<int,int>cnt;
int res=n;
for(;;){
while(t<n&&num<len){
if(cnt[a[t++]]++==0){
num++;
}
}
// printf("s=%d t=%d\n",s,t);
if(num<len)break;
res=min(res,t-s);
if(--cnt[a[s++]]==0){
num--;
}
}
printf("%d\n",res);
}
int main(){
// freopen("in.txt", "r", stdin);
// freopen("out.txt", "w", stdout);
scanf("%d",&n);
getchar();
for(int i=0; i<n; i++){
scanf("%c",&s[i]);
a[i]=s[i]-'A';
// printf("a[%d]=%d\n",i,a[i]);
}
solve();
return 0;
}
传送门:D. As Fast As Possible (math)
题意:~
思路:对于最小时间,一定满足所有的队伍同时到达终点,也就是所有的队伍走路和坐车的时间是相同的。
也就是说汽车运最后一组学生和第一组学生同时到达终点,这里要好好推敲一下,画图看看,就知道求的是一个数学的追及问题
最后推出的公式可以人工求解,也可以二分
CF拿初中题来考,不要被吓得不敢做。。。。
#include <bits/stdc++.h>
#define ll __int64
#define pr(x) cout << #x << "= " << x << " "
#define pl(x) cout << #x << "= " << x << endl;
using namespace std;
const int inf=0x3f3f3f3f;
int n, k;
double l, v1, v2;
int main(){
// freopen("in.txt", "r", stdin);
// freopen("out.txt", "w", stdout);
while (cin >> n >> l >> v1 >> v2 >> k) {
double a = (v2 - v1) /(v2 + v1) * v1 + v1;
double b = (k + n - 1) / k - 1;
double t2 = l / (a * b + v2);
double t1 = (l - v2 * t2) / v1;
printf("%.14f\n", t1 + t2);
}
return 0;
}
小结:这场CF以初中题见长啊,这让大学生有些GG........