题目链接:http://codeforces.com/contest/864
A. Fair Game
题意:水题,不说了,就是把所有数丢到set判断set的size是不是等于2,并且这两个元素出现的次数是否相等。
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
int n, x, a[110];
int main()
{
scanf("%d", &n);
set <int> s;
map <int,int> mp;
while(n--){
scanf("%d", &x);
s.insert(x);
mp[x]++;
}
if(s.size()==2 && mp[*s.begin()] == mp[*s.rbegin()]){
puts("YES");
printf("%d %d\n", *s.begin(), *s.rbegin());
}
else{
puts("NO");
}
}
B. Polycarp and Letters
题意:选择一个可以不连续的子串,问这个字串是否都是小写字母,并且每个小写字母只能出现一次,还有两个小写字母之间不能有大写字母,问这个字串的最大字符数是多少?
解法:枚举起点,终点,用set来判。中间碰到大写字母continue掉。
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
char s[200];
int main(){
int n;
int ans = 0;
scanf("%d", &n);
scanf("%s", s+1);
for(int i=1; i<=n; i++){
for(int j=i; j<=n; j++){
bool flag = 1;
set <char> ss;
for(int k=i; k<=j; k++){
if(isupper(s[k])){
flag = 0;
break;
}
ss.insert(s[k]);
}
if(flag&&ss.size()<=j-i+1){
ans = max(ans, (int)ss.size());
}
}
}
printf("%d\n", ans);
return 0;
}
C. Bus
题意:一辆车在水平路线上行驶,行驶到a又转向到0行驶,汽车有一个油箱最多***的油,路上有个加油站在f位置,问汽车走k趟最少需要加多少次油?一趟就是0->a或者a->0
解法:模拟题,注意最后一趟的情况即可。
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
int main()
{
LL a,b,f,k;
scanf("%lld%lld%lld%lld", &a,&b,&f,&k);
int cap = b;
int offset = 0;
int ans = 0;
bool can=1;
while(k--){
if(offset==0){
b-=f;
if(b < 0){
can = 0;
break;
}
if(k==0){
if(b<a-f){
ans++;
b=cap;
}
}
else{
if(b<(a-f)*2){
ans++;
b=cap;
}
}
b -= a-f;
if(b<0){
can = 0;
break;
}
}
else{
b-=a-f;
if(b < 0){
can = 0;
break;
}
if(k==0){
if(b<f){
ans++;
b=cap;
}
}
else{
if(b<2*f){
ans++;
b=cap;
}
}
b-=f;
if(b<0){
can=0;
break;
}
}
offset^=1;
}
if(can==0) puts("-1");
else printf("%d\n", ans);
return 0;
}
D. Make a Permutation!
题意:给了一个n个数的序列,现在要把这n个数变成一个排列,问最少的改变数的次数,在次数最少的情况下保证字典序最小。
解法:用一个set把没有访问的数丢进去,扫到序列出现多次 的数的第一次,用set里面最小的数去尝试替换在序列里出现多次的数,第二次及以后扫描到的话就直接替换,这样就可以保证字典序最小了。
#include <bits/stdc++.h>
using namespace std;
const int maxn = 2e5+10;
int n, a[maxn];
set <int> s1;
map <int, int> mp;
bool vis[maxn];
int main()
{
scanf("%d", &n);
mp.clear();
for(int i=1; i<=n; i++) s1.insert(i);
for(int i=1; i<=n; i++){
scanf("%d", &a[i]);
if(s1.find(a[i]) != s1.end()){
s1.erase(a[i]);
}
mp[a[i]]++;
}
int ans = 0;
memset(vis,0,sizeof(vis));
for(int i=1; i<=n; i++){
if(mp[a[i]]==1&&!vis[a[i]]){
a[i] = a[i];
mp[a[i]]--;
}
else if(mp[a[i]]>1&&!vis[a[i]]){
mp[a[i]]--;
if(*s1.begin()<a[i]){
a[i] = *s1.begin();
s1.erase(a[i]);
ans++;
}
else{
a[i] = a[i];
}
vis[a[i]] = 1;
}
else{
a[i] = *s1.begin();
s1.erase(a[i]);
ans++;
}
}
printf("%d\n", ans);
for(int i=1; i<=n; i++) printf("%d ", a[i]);
printf("\n");
return 0;
}
E. Fire
题意:需要去拯救n个物品,对于每个物品有拯救这个物品的时间,这个物品完全被能被拯救的截止时间和这个物品的价值,问能拯救的物品的最大价值,并输出拯救了哪些物品。
解法:首先按照d的大小对物品排序,然后这就转化成了一个01背包问题,我们在背包转移的时候记录下路径就可以了,dp[i][j]代表第i个个物品在j时间拯救的最大价值。
#include <bits/stdc++.h>
using namespace std;
const int maxn = 2005;
int n, dp[105][maxn], pre[105][maxn];
struct node{
int t, d, p, id;
node(){}
node(int t, int d, int p, int id):t(t),d(d),p(p),id(id){}
bool operator<(const node &rhs) const{
return d < rhs.d;
}
}p[maxn];
int main()
{
scanf("%d", &n);
for(int i=1; i<=n; i++){
scanf("%d %d %d", &p[i].t,&p[i].d,&p[i].p);
p[i].id = i;
}
memset(dp, 0x80, sizeof(dp));
dp[0][0] = 0;
sort(p+1, p+n+1);
for(int i=1; i<=n; i++){
int t = p[i].t;
int d = p[i].d;
int pp = p[i].p;
for(int j=0; j<maxn; j++){
if(dp[i-1][j]>=0){
if(dp[i-1][j]>dp[i][j]){
dp[i][j]=dp[i-1][j];
pre[i][j]=j;
}
if(j+t<d){
if(dp[i-1][j]+pp>dp[i][j+t]){
dp[i][j+t] = dp[i-1][j]+pp;
pre[i][j+t] = j;
}
}
}
}
}
int v = max_element(dp[n], dp[n]+maxn)-dp[n];
int ans = dp[n][v];
printf("%d\n", ans);
stack <int> s;
for(int i=n; i>=1; i--){
if(v != pre[i][v]){
s.push(p[i].id);
}
v = pre[i][v];
}
printf("%d\n", (int)s.size());
while(!s.empty()){
printf("%d ", s.top());
s.pop();
}
printf("\n");
return 0;
}
F:
题意:给你一个有向图,问任意两点间的字典序最小路径(如果存在)上的第k个节点是啥
解法:膜了一发题解。http://blog.csdn.net/weixin_37517391/article/details/78105828?locationNum=2&fps=1 如果不考虑环的情况,那么我们可以把从起点相同的询问放在一起来操作,然后从s点开始按照字典序选边,跑一边dfs,用栈来存储当前的路径。每到一个t点的时候。回答一下<s,t>的询问,即拿出栈中第k个位置的点,这样的话,我们跑n次dfs就可以回答所有的询问了(offline操作)。
现在问题变难了,如果有环的话,字典序最小的路径有可能不存在。这就需要我们在dfs的过程中进行判环,想到使用tarjan算法。
我们每次dfs一个点u的时候,令low[u] = inf;这样的话,如果判断有dfn[u]>=low[u](含义就是出现了一个字典序小的环)那么从经由u到达的其他点的答案均为-1了。
#include <bits/stdc++.h>
using namespace std;
const int inf = 0x3f3f3f3f;
const int maxn = 3010;
const int maxq = 4e5+10;
struct node{
int id,x,y,k;
node(){}
node(int id, int x, int y, int k):id(id),x(x),y(y),k(k){}
bool operator<(const node &rhs) const{
return x < rhs.x;
}
}qs[maxq];
vector <node> Q[maxn];
int n, m, q, ans[maxq];
int dfsclk, top;
int dfn[maxn], low[maxn], instk[maxn], stk[maxn];
vector <int> G[maxn];
void dfs(int u, int ok){
dfn[u] = ++dfsclk;
low[u] = inf;
stk[top++] = u;
instk[u] = 1;
if(ok){
for(int i=0; i<Q[u].size(); i++){
if(Q[u][i].k <= top) ans[Q[u][i].id] = stk[Q[u][i].k-1];
}
}
for (int i=0; i<G[u].size(); i++){
int v = G[u][i];
if (!dfn[v]){
dfs(v, ok && dfn[u] < low[u]);
low[u] = min(low[u], low[v]);
}
else if (instk[v]){
low[u] = min(low[u], dfn[v]);
}
}
instk[u] = 0;
--top;
}
int main(){
scanf("%d %d %d", &n,&m,&q);
for(int i=1; i<=m; i++){
int u, v;
scanf("%d %d", &u,&v);
G[u].push_back(v);
}
for(int i=1; i<=n; i++) sort(G[i].begin(), G[i].end());
for(int i=0; i<q; i++){
int x,y,k;
scanf("%d %d %d", &x,&y,&k);
qs[i] = node(i,x,y,k);
}
sort(qs, qs+q);
memset(ans, -1, sizeof(ans));
for(int i=0; i<q; i++){
Q[qs[i].y].push_back(qs[i]);
if(qs[i].x != qs[i+1].x){
memset(dfn, 0, sizeof(dfn));
memset(instk, 0, sizeof(stk));
memset(low, 0, sizeof(low));
top = dfsclk = 0;
dfs(qs[i].x, 1);
for(int j=1; j<=n; j++) Q[j].clear();
}
}
for(int i=0; i<q; i++) printf("%d\n", ans[i]);
return 0;
}