7763
题意:有m份彩票,n个人,已知第i份彩票的奖金是 2^i 元,已知每个人买的不同彩票的数量,已知每张彩票中奖的概率是相等的,问对于每个人来说,得到的奖金比别的所有人的奖金都多的概率。
思路:看起来很吓人要算这样奇葩的概率。。。但是2^m > 2^(m-1) + ... + 2^1。。。所以最后的概率就是该人买的第m份彩票中奖的概率。。。
#include <cstdio>
#define N 10005
int n, m, useless;
int total, p[N];
int gcd(int a, int b)
{
if (a == 0) return b;
if (b == 0) return a;
int mod;
while (mod = a % b)
{
a = b;
b = mod;
}
return b;
}
int main()
{
while (true)
{
scanf("%d%d",&n,&m);
if (n == 0 && m == 0) break;
total = 0;
for (int i = 0; i < n; ++ i)
{
for (int j = 0; j < m; ++ j)
scanf("%d",&useless);
total += useless;
p[i] = useless;
}
for (int i = 0; i < n; ++ i)
{
useless = gcd(p[i], total);
p[i] /= useless;
printf("%d / %d\n", p[i], total/useless);
}
}
}
7764:
题意:n个政党,给出他们的名字,和相应的得票率(一位的浮点数)。再给出g个猜测,猜测的格式是 XX + YY + ... = n,n是整数,XX,YY是政党名字,问这些猜测是否正确。
思路:坑爹的是浮点数是会有误差的,然后由于是一位的浮点数。。。我就采用了最无聊的办法。。。把那位小数和整数单独存起来。。。应该可以用其他的例如允许eps之类的吧。。。当时懒得了。。。
#include <iostream>
#include <cstdio>
#include <cmath>
using namespace std;
#define eps 1e-6
int p, g, n, flag;
string par[55], tstr;
int z[55], f[55], tz, tf;
int index(string &st)
{
for (int ret = 0; ret < p; ++ ret)
if (par[ret] == st) return ret;
return -1;
}
int main()
{
while (scanf("%d%d",&p,&g) != EOF)
{
for (int i = 0; i < p; ++ i)
{
cin >> par[i];
scanf("%d.%d",&z[i],&f[i]);
}
for (int Case = 1; Case <= g; ++ Case)
{
cin >> tstr;
tz = z[index(tstr)];
tf = f[index(tstr)];
while (true)
{
cin >> tstr;
if (tstr == "+")
{
cin >> tstr;
tz += z[index(tstr)];
tf += f[index(tstr)];
}
else if (tstr == "<")
{
tz += tf / 10;
tf %= 10;
cin >> n;
flag = tz<n ? 1 : 0;
break;
}
else if (tstr == ">")
{
tz += tf / 10;
tf %= 10;
cin >> n;
flag = tz>n || (tz==n&&tf!=0) ? 1 : 0;
break;
}
else if (tstr == ">=")
{
tz += tf / 10;
tf %= 10;
cin >> n;
flag = tz>=n ? 1 : 0;
break;
}
else if (tstr == "<=")
{
tz += tf / 10;
tf %= 10;
cin >> n;
flag = tz<n || (tz==n&&tf==0) ? 1 : 0;
break;
}
else if (tstr == "=")
{
tz += tf / 10;
tf %= 10;
cin >> n;
flag = tz==n&&tf==0 ? 1 : 0;
break;
}
}
printf("Guess #%d was %s.\n", Case, flag?"correct":"incorrect");
}
}
}
7765:
题意:求1~n的一个排列,满足两个性质:(1)完全不单调性,即对于任意连续的三个数,中间的数最大或者最小。(2)唯一循环性,也就是从第一个数开始,把它当作位置的指针,依次指下去,会遍历这n个数回到第一个数。
思路:开始没人做,坑爹啊,后来发现很水有木有。。。明明是稍加构造直接okay的。。。
#include <cstdio>
int n, ans[1000005];
int main()
{
while (scanf("%d",&n), n)
{
ans[1] = 1;
for (int i = 2; i <= n; ++ i)
{
if (i&1)
{
ans[i] = ans[i-2];
ans[i-2] = i;
}
else
{
ans[i] = ans[i-1];
ans[i-1] = i;
}
}
for (int i = 1; i <= n; ++ i)
printf("%d%c", ans[i], i==n?'\n':' ');
}
}
7766:
思路:如题,裸的最小生成树
#include <cstdio>
#include <queue>
#include <vector>
using namespace std;
const int MAXN = 200005;
int m, n, ans;
int root[MAXN];
void init() {
for (int i = 0; i < MAXN; ++ i)
root[i] = i;
}
int Find(int x) {
int t, r = root[x];
while (root[r] != r) r = root[r];
while (root[x] != r) {
t = root[x];
root[x] = r;
x = t;
}
return r;
}
void Merge(int x, int y) {
int fx = Find(x), fy = Find(y);
if (fx != fy) root[fx] = fy;
}
struct Edge {
int st, ed, len;
Edge() {}
Edge(int _s, int _e, int _l): st(_s), ed(_e), len(_l) {}
bool operator < (const Edge &e) const {
return len < e.len;
}
bool operator > (const Edge &e) const {
return len > e.len;
}
};
priority_queue<Edge, vector<Edge>, greater<Edge> > Q;
int Kruskal() {
int ans = 0;
init();
Edge e;
int fx, fy;
while (!Q.empty()) {
e = Q.top();
Q.pop();
fx = Find(e.st);
fy = Find(e.ed);
if (fx != fy) {
Merge(e.st, e.ed);
ans += e.len;
}
}
return ans;
}
int main()
{
while (true)
{
scanf("%d%d",&n,&m);
if (n==0 && m==0) break;
ans = 0;
init();
for (int i=0, st, ed, len; i < m; ++ i)
{
scanf("%d%d%d",&st,&ed,&len);
ans += len;
Q.push(Edge(st,ed,len));
}
printf("%d\n", ans-Kruskal());
}
}
7767:(!)
题意:没看
思路:等题解
7768:(!)
题意:n个学生吃饭,他们的饭量y[1,...,n]已给出,而每一份饭的份量未知,给出常数a,b,定义学生的消耗 = a*浪费的饭量 + b*打饭的次数。要求每个学生打饭不超过三次,问学生的消耗和最少是多少。
思路:(TLE)我想,学生只有1000个的话,那么每份饭的分量就只有y[i]/1,y[i]/2,y[i]/3这3000种可能,那么对这3000种份量计算总学生的消耗,就是3000*1000次计算,超时,可以二分查找最少的份量(因为每个学生打饭不超过三次,必定有一个份量下界),只计算前若干种(大约50种?)情况,但还是超时。
7769:
题意:给出一个生成随机数的方法(对于一个四位数,不断的平方,取中间四位数),问给出一个最初数的情况下最多能产生多少个“随机数”?
思路:如题
#include <cstdio>
#include <cstring>
bool vis[10005];
int ans, n;
int main()
{
while (scanf("%d",&n) && n)
{
memset(vis, 0, sizeof(vis));
ans = 0;
while (!vis[n])
{
ans ++;
vis[n] = true;
n = (n*n/100) % 10000;
}
printf("%d\n", ans);
}
}
7770:
题意:有n(上限10000)个城市,h(上限100)个城市有旅馆,现在要从城市1到达城市n。给出m(100000)条路径,每条都是双向的路经,从a到b的时间t。已知不能不休息地行驶600分钟,问最少要休息多少次才能到达。
思路:做SPFA,直接TLE,分析原因。
发现如果两个城市之间有不超过600的路径且都有旅馆,就会在两个城市之间来回(休息天数不断增多),这样是徒劳的,要避免这种状况,就对每个状态增加了是否在这100个旅馆休息过(显然每个旅馆最多只可能待一夜,如果是最佳方案的话)。
这样的话还是会有问题,就是如果两个城市之间存在长度为1的路径,那么就会在两个城市之间来来回回,于是再增加筛选条件,就是休息了d次到达k城市的最少连续行驶时间,如果要推入的状态比这个大,那么直接舍弃。
代码很渣, 因为是不断修改的。。。
#include <iostream>
#include <cstdio>
#include <cstring>
#include <vector>
#include <queue>
using namespace std;
#define N 10005
int n, h, m;
bool hot[105];
int pnt[N]; // hotel
struct Edge
{
int e, w;
Edge() {}
Edge(int _e, int _w): e(_e), w(_w) {}
};
vector <Edge> adj[N];
struct Item
{
int d, t, l;
bool vis[105];
Item() { memset(vis,0,sizeof(vis)); }
Item(int _d, int _t, int _l): d(_d), t(_t), l(_l) { memset(vis,0,sizeof(vis)); }
bool operator < (const Item &ob) const
{
if (d != ob.d) return d > ob.d;
if (t != ob.t) return t > ob.t;
return l != n;
}
void print()
{
printf("%d %d %d ", l, t, d);
for (int i = 0; i < 4; ++ i) printf("%d",vis[i]);
printf("\n");
}
} cur, nxt;
int best[N][105];
int calc()
{
priority_queue <Item> Q;
Q.push(Item(0,0,1));
best[1][0] = 0;
while (!Q.empty())
{
cur = Q.top();
//cur.print();
Q.pop();
if (cur.l == n) return cur.d;
if (best[cur.l][cur.d] != cur.t) continue;
for (int i = 0; i < adj[cur.l].size(); ++ i)
{
nxt = cur;
nxt.l = adj[cur.l][i].e;
nxt.t = cur.t + adj[cur.l][i].w;
if (nxt.t > 600)
{
if (cur.t != 0 && pnt[cur.l]>0 && !nxt.vis[pnt[cur.l]])
{
nxt.d ++;
nxt.l = cur.l;
nxt.t = 0;
nxt.vis[pnt[cur.l]] = true;
best[nxt.l][nxt.d] = 0;
Q.push(nxt);
}
}
else
{
if (best[nxt.l][nxt.d] > nxt.t)
{
Q.push(nxt);
best[nxt.l][nxt.d] = nxt.t;
}
}
}
}
return -1;
}
int main()
{
while (scanf("%d",&n), n)
{
for (int i = 1; i <= n; ++ i)
{
adj[i].clear();
for (int j = 0; j < 105; ++ j)
best[i][j] = 601;
pnt[i] = -1;
}
scanf("%d",&h);
for (int i=0, cnt=1, c; i < h; ++ i)
{
scanf("%d",&c);
pnt[c] = cnt++;
}
scanf("%d",&m);
for (int i=0, st, ed, w; i < m; ++ i)
{
scanf("%d%d%d",&st,&ed,&w);
adj[st].push_back(Edge(ed,w));
adj[ed].push_back(Edge(st,w));
}
printf("%d\n", calc());
}
}