题目链接:http://codeforces.com/contest/767
A. Snacktower
题意:给你n个数,从1到n乱序,让你从大到小输出,而且要根据先入后出的顺序,输出n行,如果当前行无法输出就直接换行再满足条件行一起输出。
解法:直接开两个数组,一个数组存储n个数,;另外一个数组判断这个数是否已经存入来输出。
#include
using namespace std;
const int maxn = 100005;
int n, a[maxn], b[maxn];
int main(){
scanf("%d", &n);
int t = n;
for(int i=1; i<=n; i++){
scanf("%d", &a[i]);
b[a[i]] = 1;
for(;b[t]==1;t--) printf("%d ",t);
printf("\n");
}
}
题意:有个人需要办理一个证件,证件办理处开门的时间是ta到tb,办理一个证件需要t的时间,现在有n个人,知道n个人来的时间,求这个办理证件的人在什么时间来等待的时间最少
解法:肯定要在某个人前一秒到达,到的更早没有意义,到的更晚就被他抢先了。 这样可以O(n)枚举一遍解决。 但是要考虑各种情况,比如在所有人之后到、别人到的时间都不在规定时间内。
#include
using namespace std;
typedef long long LL;
int main(){
LL a, b, t;
scanf("%lld %lld %lld", &a,&b,&t);
LL maxx = 1e12;
LL ans = 0;
int n;
scanf("%d", &n);
while(n--){
LL k;
scanf("%lld", &k);
if(k<=b-t){
if(k&&max(a,k-1)<=b-t&&(a-k+1)
题意:给你一颗有n个节点的树,每个节点都有一个值,问你是否能删去两条边使删后的三块值的和都相等
解法:首先判断所有数的和是不是能整除3,能的话直接DFS子树的和能得到sum/3的点,得到一个之后标记这个子树不可用,再DFS一遍即可。
#include
using namespace std;
const int inf = 0x7fffffff;
const int maxn = 1000010;
const double eps = 1e-9;
typedef long long LL;
inline int read()
{
char ch=getchar();
int f=1,x=0;
while(!(ch>='0'&&ch<='9')){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=x*10+(ch-'0');ch=getchar();}
return x*f;
}
inline LL llread(){
char ch=getchar();
LL f=1,x=0;
while(!(ch>='0'&&ch<='9')){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=x*10+(ch-'0');ch=getchar();}
return x*f;
}
int n, a[maxn], sz[maxn] , head[maxn], edgecnt, sum, ans, vis[maxn], id[maxn];
int chooseedge;
struct edge{
int v, nxt;
edge(){}
edge(int v, int nxt) : v(v), nxt(nxt) {}
}E[maxn*4];
void init(){
memset(head, -1, sizeof(head)); edgecnt = 0;
}
void addedge(int u, int v){
E[edgecnt].v = v, E[edgecnt].nxt = head[u], head[u] = edgecnt++;
}
void dfs(int u, int fa){
sz[u] = a[u];
for(int i = head[u]; ~i; i = E[i].nxt){
int v = E[i].v;
if(v == fa) continue;
if(v == chooseedge || v == 0) continue;
dfs(v, u);
sz[u] += sz[v];
if(sz[v] == sum){
printf("%d %d\n", ans + 1, i / 2 + 1);
exit(0);
}
}
}
void dfs1(int u, int fa){
sz[u] = a[u];
for(int i = head[u]; ~i; i = E[i].nxt){
int v = E[i].v;
if(v == fa) continue;
if(v == 0) continue;
dfs1(v, u);
sz[u] += sz[v];
if(sz[v] == sum){
vis[v] = 1;
id[v] = i / 2;
ans = id[v];
chooseedge = v;
dfs(1, 0);
puts("-1");
exit(0);
}
}
}
int main(){
init();
n = read();
for(int i = 1; i <= n; i++){
int u = read(), v = read();
addedge(u, i);
addedge(i, u);
sum += v;
a[i] = v;
}
if(sum % 3 || sum == 0){puts("-1"); return 0;}
sum /= 3;
dfs1(1, 0);
}
D. Cartons of milk
题意:主人公很喜欢喝牛奶,每天会喝K盒,如果不足K盒,就会将所有拥有的都喝了。
不傻的人都知道,牛奶过期了之后肯定就不能喝了,那就只能扔掉。
现在冰箱中有N盒牛奶,超市中有M盒牛奶,如果冰箱中的牛奶喝不完就有浪费的情况出现,输出-1,否则输出能够在超时中购买的牛奶数量的最大值。
并且输出可以购买的牛奶的编号。
解法:首先将冰箱的牛奶排升序, 商店的牛奶排降序(商店的要用结构存编号,因为答案要输出)。然后再二分购买牛奶的瓶数。测试牛奶是否喝的完的时候,一瓶一瓶地模拟就是了,喝完了k瓶,然后又到了新的一天。复杂度O(mlogm)
#include
using namespace std;
const int maxn = 1e6+10;
struct node{
int x, id;
bool operator<(const node &rhs){
return xm||a[p1]
题意:
一共有两种货币:100块的和1块的.一开始有m个1块的,和无限个100块的.
一共有N天,其中每天的饭钱是ci.每天收银员的怒气值是wi.
对应一天收银员不高兴的值会增长:找零钱的数量(100块的和1块的找零总数)*wi.
收银员很聪明,他肯定给你找零是最小的数量。
就是说假如今天饭钱是165.假如你给他300,他一定找你一张100的和35个一块的。
这N天是按照时间顺序给出的,不能打乱,问最终收银员这N天积累的不高兴值最高是多少。
对应每天给收银员的货币情况是什么。
解法:
一个非常神奇的贪心。。。
1、
①首先,如果m>=a[i].ci%100.那么对应这天直接用1块a[i].ci%100个.以及100块a[i].ci/100个。
②否则,如果遇到了m=a[i].ci%100.
2、那么这个“有些天”如何控制呢?想了很久,后来才发现一个关键点:对于之前的某天,如果他选择的方式①支付,那么他那天就支付了a[那天].ci%100个1块的硬币,那么如果我们那天改变成②方式支付,那么相当于到这一天,多了100硬币出来,我们肯定一点,100+m是一定>=a[i].ci%100的,所以只要找到之前某一天,选择的方式①支付,我们改成方式②去支付,就能够使得今天的1块钱够用。