MARK一下~~
http://acm.csu.edu.cn/OnlineJudge/contestrank.php?cid=2098
A:
题意:给出几个树,让你用最少的边将他们联通,且树的直径最小~
思路:
求出每个树的直径,把其看成一个链,那么肯定是将链的中点连到一起才能使最后直径最短,然后因为直径有可能相等,最多用2条边连出一条直径,所以讨论一下用0,1,2条边连的情况,取最大值就ok了!
这里求树的直径采用了双BFS法,因为是bfs,所以两次都一定找到的是端点~
#include <iostream>
#include <cstring>
#include <algorithm>
#include <cstdio>
#include <queue>
#define mem0(a) memset(a,0,sizeof(a))
using namespace std;
template<class T> T MAX(T a, T b) { return a > b ? a : b; }
template<class T> T MIN(T a, T b) { return a < b ? a : b; }
const int maxn = 200010;
int hh[maxn];
struct nod {
int to,next,w;
} edge[maxn];
int head[maxn],ip;
int n,m;
bool vis1[maxn], vis2[maxn];
vector<int>dd;
int dis1[maxn], dis2[maxn];
int f(int x){
return (x+1)/2;
}
void init() {
ip=0;
memset(head,-1,sizeof(head));
}
void add(int u,int v,int w) {
edge[ip].to=v;
edge[ip].w=w;
edge[ip].next=head[u];
head[u]=ip++;
}
void BFS1(int u, int &ans, int &lv) {
queue<int > Q;
Q.push(u);
vis1[u]=1;
while(!Q.empty()) {
int top = Q.front();
Q.pop();
for(int i=head[top]; i!=-1; i=edge[i].next) {
int v = edge[i].to;
hh[v]=1;
if(!vis1[v]) {
vis1[v]=1;
Q.push(v);
dis1[v]=dis1[top]+edge[i].w;
if(ans < dis1[v]){
ans = dis1[v];
lv = v;
}
}
}
}
}
void BFS2(int u, int &ans, int &lv) {
queue<int > Q;
Q.push(u);
vis2[u]=1;
while(!Q.empty()) {
int top = Q.front();
Q.pop();
for(int i=head[top]; i!=-1; i=edge[i].next) {
int v = edge[i].to;
hh[v]=1;
if(!vis2[v]) {
vis2[v]=1;
Q.push(v);
dis2[v]=dis2[top]+edge[i].w;
if(ans < dis2[v]){
ans = dis2[v];
lv = v;
}
}
}
}
}
int TreeDiameter(int k) {
int ans = 0;
int u = 0;
BFS1(k, ans, u);
ans = 0;
BFS2(u, ans, u);
return ans;
}
int main() {
while(~scanf("%d%d",&n,&m)){
mem0(hh);dd.clear();
memset(vis1,0,sizeof(vis1));
memset(dis1,0,sizeof(dis1));
memset(vis2,0,sizeof(vis2));
memset(dis2,0,sizeof(dis2));
init();
for(int i=0; i<=m-1; i++) {
int u,v;
scanf("%d%d",&u,&v);
add(u+1,v+1,1);
add(v+1,u+1,1);
}
int D ;
int maxxx=0;
for(int i=1;i<=n;i++){
if(hh[i]==0){
D = TreeDiameter(i);
maxxx=MAX(maxxx,D);
dd.push_back(f(D));
}
}
sort(dd.begin(),dd.end());
int size=dd.size();int ans=0;
ans=max(ans,maxxx);
if(dd.size()>=2)ans=max(ans,dd[size-1]+dd[size-2]+1);
if(dd.size()>=3)ans=max(ans,dd[size-2]+dd[size-3]+2);
printf("%d\n",ans);
}
return 0;
}
B:
题意:求小于等于8的全排列,且相邻排列必须保证只有一步之差~
思路:构造题,首先递归求出n-1的,然后考虑插n,从右开始,每次都与左边一个交换位置~到最左边后则直接插在下一个n-1的最前面,这个可以用数学归纳法证明2个肯定一步之差~(子问题),然后往右的时候亦然~
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define gmax(a, b) ((a) > (b) : (a) : (b))
#define gmin(a, b) ((a) < (b) : (a) : (b))
#define mem0(a) memset(a,0,sizeof(a))
#define mem_1(a) memset(a,-1,sizeof(a))
#define FIN freopen("in.txt", "r", stdin)
#define FOUT freopen("out.txt", "w", stdout)
int n;
vector<vector<int> > dfs(int n){
if(n==1) {
vector<vector<int> > a;
vector<int>b;b.push_back(1);a.push_back(b);return a;
}
vector<vector<int> > o=dfs(n-1);
vector<vector<int> > oo;
int flag=1;int pos;
for(int i=0;i<o.size();i++){
int m=o[i].size();
int cur=flag?n-1:0;
if(flag)o[i].push_back(n);
else o[i].insert(o[i].begin(),n);
oo.push_back(o[i]);
for(int j=0;j<m;j++){
if(flag) pos=cur-1;
else pos=cur+1;
swap(o[i][pos],o[i][cur]);
cur=pos;
oo.push_back(o[i]);
}
flag^=1;
}
return oo;
}
int main(){
scanf("%d",&n);
vector<vector<int> >ans=dfs(n);
for(int i=0;i<ans.size();i++){
int m=ans[i].size();
for(int j=0;j<m-1;j++){
printf("%d ",ans[i][j]);
}
printf("%d\n",ans[i][m-1]);
}
}
C:
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define gmax(a, b) ((a) > (b) : (a) : (b))
#define gmin(a, b) ((a) < (b) : (a) : (b))
#define mem0(a) memset(a,0,sizeof(a))
#define mem_1(a) memset(a,-1,sizeof(a))
#define FIN freopen("in.txt", "r", stdin)
#define FOUT freopen("out.txt", "w", stdout)
char tmp[4]={"PER"};
char s[310];
typedef pair<int,int> pii;
int main(){
scanf("%s",s);int ans=0;
for(int i=0;i<strlen(s);i++){
if(s[i]!=tmp[i%3]) ans++;
}
printf("%d\n",ans);
return 0;
}
D:
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define gmax(a, b) ((a) > (b) : (a) : (b))
#define gmin(a, b) ((a) < (b) : (a) : (b))
#define mem0(a) memset(a,0,sizeof(a))
#define mem_1(a) memset(a,-1,sizeof(a))
#define FIN freopen("in.txt", "r", stdin)
#define FOUT freopen("out.txt", "w", stdout)
const int manx=1e5+10;
int n,k;
queue<int >q;
int b;
typedef pair<int,int> pii;
int main(){
scanf("%d%d",&n,&k);int ans=0;
for(int i=1;i<=n;i++){
scanf("%d",&b);q.push(b);
while(!q.empty()&&q.back()-q.front()>=1000){
q.pop();
}
ans=max(ans,((int)q.size()+k-1)/k);
}
printf("%d\n",ans);
return 0;
}
E:
贪心
每次都给后面的任务留出更早的结束时间~
这里注意erase(it)不是*it !!!
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define gmax(a, b) ((a) > (b) : (a) : (b))
#define gmin(a, b) ((a) < (b) : (a) : (b))
#define mem0(a) memset(a,0,sizeof(a))
#define mem_1(a) memset(a,-1,sizeof(a))
#define FIN freopen("in.txt", "r", stdin)
#define FOUT freopen("out.txt", "w", stdout)
const int maxn=1e5+10;
struct D
{
int x;
bool operator < (const D& rbs)const{
return x > rbs.x;
}
D(){}
D(int _x){x = _x;
}
};
int n,k;
struct node{
int x,y;
}a[maxn];
multiset<D>s;
bool cmp(node a,node b){
return a.y<b.y;
}
int main(){
while( scanf("%d%d",&n,&k)!=EOF){
s.clear();
for(int i=1;i<=n;i++){
scanf("%d%d",&a[i].x,&a[i].y);
}
sort(a+1,a+1+n,cmp);int ans=0;
for(int i=1;i<=n;i++){
multiset<D>::iterator it=s.lower_bound(D(a[i].x));
//printf("%d\n",(*it).x);
if(it!=s.end()){
s.erase(it);
ans++;s.insert(D(a[i].y));
}
else if(s.size()<k){
s.insert(D(a[i].y));ans++;
}
}
printf("%d\n",ans);
}
}
F:
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define gmax(a, b) ((a) > (b) : (a) : (b))
#define gmin(a, b) ((a) < (b) : (a) : (b))
#define mem0(a) memset(a,0,sizeof(a))
#define mem_1(a) memset(a,-1,sizeof(a))
#define FIN freopen("in.txt", "r", stdin)
#define FOUT freopen("out.txt", "w", stdout)
const int manx=1e5+10;
int n,k;
set<int>s,ss;
queue<int >q;
typedef pair<int,int> pii;
const int maxn=1e4+10;
int f,t[maxn];
int st,e,a,b;
int main(){
scanf("%d",&f);int flag=1;
for(int i=1;i<=f;i++){
scanf("%d%d",&a,&b);s.clear();
for(int i=0;i<=a;i++){
s.insert(i);
}
for(int i=0;i<b;i++){
scanf("%d%d",&st,&e);ss.clear();
for(set<int>::iterator it=s.begin();it!=s.end();it++){
if((*it-(e-st))>=0) ss.insert((*it-(e-st)));
if((*it+(e-st))<=a) ss.insert((*it)+(e-st));
}
if(ss.empty()) {
flag=0;continue;
}
swap(s,ss);
}
}
if(!flag) printf("impossible\n");
else puts("possible");
}
数据结构题,从半径入手,对每个x记录y的位置,然后判断边界二分就可了 ,详见代码~
G:
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define gmax(a, b) ((a) > (b) : (a) : (b))
#define gmin(a, b) ((a) < (b) : (a) : (b))
#define mem0(a) memset(a,0,sizeof(a))
#define mem_1(a) memset(a,-1,sizeof(a))
#define FIN freopen("in.txt", "r", stdin)
#define FOUT freopen("out.txt", "w", stdout)
const int maxn=1e5+10;
multiset<int>mx[1010];
struct Node{
int x,y;
}p[maxn];
struct node{
int x,y,r;
}a[2010];
int n,m;
int main(){
scanf("%d",&n);int xa,ya;int x,y,r;
for(int i=1;i<=n;i++){
scanf("%d%d",&xa,&ya);
mx[xa].insert(ya);
}
scanf("%d",&m);
for(int i=1;i<=m;i++){
scanf("%d%d%d",&x,&y,&r);
for(int xx=max(0,x-r);xx<=min(10000,x+r);xx++){
int maxx=0;int minn=1000000007;
for(int yy=max(0,y-r);yy<=min(10000,y+r);yy++){
if((xx-x)*(xx-x)+(yy-y)*(yy-y)<=r*r){
maxx=max(maxx,yy);minn=min(minn,yy);
}
}
multiset<int>::iterator it1=mx[xx].lower_bound(minn);
multiset<int>::iterator it2=mx[xx].upper_bound(maxx);
mx[xx].erase(it1,it2);
}
}
int ans=0;
for(int i=0;i<=10000;i++){
ans+=mx[i].size();
}
printf("%d\n",ans);
}
H:
题意:
类似于节奏大师,每次会有音符掉落,击中则得一分,首先肯定了玩家技术超强,每个音符都肯定会打掉~然后增加了一个按钮,可以在充电时间充电,可以叠加,随时停止,但一旦释放就必须放完,释放期间内的音符价值为2分,重叠的释放和充电时间音符价值为1~(如果二者恰好接壤则无影响~,价值仍为2)
思路:
动态规划,best i 表示的是在i(充电的阶段)之前能得到的最大增加分数,然后枚举在每个区间开始充电到point,所能释放电到的最大j,(双指针法), 取最大的长度更新对应的best值就可以了~,答案最后需要加上n~
注意best和start下标相差1,表示的含义正好与上面相对~
resize的含义是:
如果n比当前的vector元素数目要小,vector的容量要缩减到resize的第一个参数大小,既n。并移除那些超出n的元素同时销毁他们。
如果n比当前vector元素数目要大,在vector的末尾扩展需要的元素数目,如果第二个参数val指定了,扩展的新元素初始化为val的副本,否则按类型默认初始化。
注意:如果n大于当前的vector的容量(是容量,并非vector的size),将会引起自动内存分配。所以现有的pointer,references,iterators将会失效。
#include <iostream>
#include <vector>
#include <unordered_map>
#include <cstdio>
using namespace std;
#define rep(i,a,b) for(__typeof(b) i=a; i<(b); ++i)
typedef vector<int> vi;
void improveMax(int &a, int b)
{
a = max(a, b);
}
int main()
{
int n, p;
scanf("%d %d", &n, &p);
unordered_map<int, int> ord;
vi t(n);
rep(i,0,n) {
scanf("%d", &t[i]);
ord[t[i]] = i;
}
vi next, starts(p), totpow;
rep(i,0,p)
{
int s, e; scanf("%d %d", &s, &e);
starts[i] = ord[s];
next.resize(starts[i], i);
totpow.resize(starts[i] + 1, (totpow.empty() ? 0 : totpow.back()));
rep(j,ord[s],ord[e])
totpow.push_back(totpow.back() + t[j + 1] - t[j]);
}
totpow.resize(n, totpow.back());
next.resize(n, p);
/*for(auto i: totpow){
cout<<"totpow= "<<i<<endl;
}
for(auto i:next){
cout<<"next= "<<i<<endl;
}*/
vi best(p + 1);
rep(i,0,p)
{
int point = starts[i];
rep(j,point+1,n)
{
while (point + 1 < n && totpow[point + 1] - totpow[starts[i]] <= t[j] - t[point + 1])
point++;
// cout<<"i= "<<i<<" j= "<<j<<" "<<"point= "<<point<<endl;
improveMax(best[next[j]], best[i] + (j - point));
}
}
cout << best[p] + n << endl;
}
J:
题意:
对于每个一行的文本串,最后一个字符串是前面的问句的答案
每次可以在一个句子的一半打断他进行抢答
问最有得分的期望值
建一个字典树,字典树上的点存储的是字符串
但是本题奇特的方式在在于字典树上存储了两个值
一个是正常的文本串顺序,用于遍历和存储文本串
一个是对于每个句子的答案,有多少个句子可以在这个点回答此答案
最后按照期望DP的方式求解
标程写成递归就直接照搬了,实际上可以写成循环结构
#include <bits/stdc++.h>
using namespace std;
const int MAXN = 100000 + 5;
struct Node
{
map<string,int> next;
map<string,int> answer;
double pro;
int tot;
void clear() {next.clear(); tot = 0; answer.clear();}
}node[MAXN];
char str[MAXN];
double solve(int i, vector<double>::iterator it, int left)
{
// printf("i = %d\n", i);
if(left == 0) return 0;
double ans1 = node[i].pro + *it;
double ans2 = 0;
for(auto v : node[i].next) {
ans2 += solve(v.second, it + 1, left - 1) * node[v.second].tot;
}
return max(ans1, ans2 / node[i].tot);
}
int main()
{
int t, n;
while(scanf("%d%d", &t, &n) != EOF) {
cin.getline(str, MAXN);
int cnt = 0;
node[cnt].clear();
for(int j = 0 ; j < n ; j++){
cin.getline(str, MAXN);
string temp = "";
int index = 0;
string aanswer = "";
for(int i = strlen(str) - 1 ; i >= 0 ; i--) {
if(str[i] == ' ') break;
else aanswer += str[i];
}
// cout << " aanswer = " << aanswer << endl;
node[0].answer[aanswer]++;
for(int i = 0 ; str[i] != '\0' ; i++){
if(str[i] != ' ') temp += str[i];
else{
if(node[index].next.count(temp) == 0){
node[index].next[temp] = ++cnt;
node[cnt].clear();
}
node[index].tot++;
index = node[index].next[temp];
node[index].answer[aanswer]++;
temp = "";
}
}
node[index].tot++;
// temp += str[i];
// if(node[index].next.count(temp) == 0){
// node[index].next[temp] = ++cnt;
// node[cnt].clear();
// }
// node[index].tot++;
// index = node[index].next[temp];
// node[index].tot++;
}
for(int i = 0 ; i <= cnt ; i++){
int mmax = 0;
int sum = 0;
for(auto v : node[i].answer) mmax = max(mmax, v.second), sum += v.second;
node[i].tot = sum;
node[i].pro = 1.0 * mmax / node[i].tot;
}
// for(int i = 0 ; i <= cnt ; i++)
// printf("i = %d, pro = %f, tot = %d\n", i, node[i].pro, node[i].tot);
vector <double> best(t + 1);
for(int i = t - 1 ; i >= 0 ; i--)
best[i] = solve(0, best.begin() + i + 1, t - i);
printf("%.10f\n", best[0]);
}
return 0;
}