Andrew Stankevich's Contest #8
Solution
Problem A: NonptimalAssignments
Problem B: Cryptography
Problem C: FibonacciSubsequence
Problem D: Hexagonand Rhombic Dominoes
Problem E: StrangeLimit
Problem F: LittleMammoth
Problem G: NetworkWars
Problem H: OilDeal
Problem I: Bishopson a Toral Board
July 23th,2013 by chlxyd,xioumu
Problem A: Nonptimal Assignments
构造一个矩阵,使得题目中所给的贪心不能得到正确答案。
Solution
Tag:构造
如121
012
001
构造乱搞题,可行的做法比如对角线以下全是0,从对角线开始从1递增,最后f[1][n]变成1就可以了。方法还有非常多。
/*
* Author: chlxyd
* Created Time: 2013/7/19 12:41:14
* File Name: A.cpp
*/
#include<iostream>
#include<sstream>
#include<fstream>
#include<vector>
#include<list>
#include<deque>
#include<queue>
#include<stack>
#include<map>
#include<set>
#include<bitset>
#include<algorithm>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cctype>
#include<cmath>
#include<ctime>
using namespace std;
const double eps(1e-8);
typedef long long lint;
#define clr(x) memset( x , 0 , sizeof(x) )
#define sz(v) ((int)(v).size())
#define rep(i, n) for (int i = 0; i < (n); ++i)
#define repf(i, a, b) for (int i = (a); i <= (b); ++i)
#define repd(i, a, b) for (int i = (a); i >= (b); --i)
#define clrs( x , y ) memset( x , y , sizeof(x) )
int n ;
int a[110][110] ;
int main(){
while ( scanf("%d" , &n ) == 1 ) {
repf( i , 1 , n ) {
repf( j , 1 , i - 1 ) a[i][j] = 0 ;
repf( j , i , n )
a[i][j] = j - i + 1 ;
}
a[1][n] = 1 ;
repf( i , 1 , n ) {
repf( j , 1 , n ) {
if ( j != 1 ) printf(" " ) ;
printf("%d" , a[i][j] ) ;
}
printf("\n") ;
}
printf("\n") ;
}
}
Problem B: Cryptography
有10W个2*2的矩阵,10W次询问,每次问a到b矩阵的乘积。
Solution
Tag:数据结构
如果给的不是矩阵是树的话很快就能想到用线段树去解决,换成矩阵也是一样的,只是把数的乘法改成矩阵的乘法。
/*
* Author: chlxyd
* Created Time: 2013/7/19 13:53:57
* File Name: B.cpp
*/
#include<iostream>
#include<sstream>
#include<fstream>
#include<vector>
#include<list>
#include<deque>
#include<queue>
#include<stack>
#include<map>
#include<set>
#include<bitset>
#include<algorithm>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cctype>
#include<cmath>
#include<ctime>
using namespace std;
const double eps(1e-8);
typedef long long lint;
#define clr(x) memset( x , 0 , sizeof(x) )
#define sz(v) ((int)(v).size())
#define rep(i, n) for (int i = 0; i < (n); ++i)
#define repf(i, a, b) for (int i = (a); i <= (b); ++i)
#define repd(i, a, b) for (int i = (a); i >= (b); --i)
#define clrs( x , y ) memset( x , y , sizeof(x) )
int n , R , m ;
struct matrix {
int a[2][2] ;
void clrr() {
clr(a) ;
}
matrix operator * ( const matrix & q ) const {
matrix ret ;
ret.a[0][0] = a[0][0] * q.a[0][0] + a[0][1] * q.a[1][0] ;
ret.a[0][1] = a[0][0] * q.a[0][1] + a[0][1] * q.a[1][1] ;
ret.a[1][0] = a[1][0] * q.a[0][0] + a[1][1] * q.a[1][0] ;
ret.a[1][1] = a[1][0] * q.a[0][1] + a[1][1] * q.a[1][1] ;
repf( i , 0 , 1 )
repf( j , 0 , 1 )
ret.a[i][j] %= R ;
return ret ;
}
void show() {
printf("%d %d\n" , a[0][0] , a[0][1] ) ;
printf("%d %d\n" , a[1][0] , a[1][1] ) ;
}
};
struct treetype {
matrix a ;
int l , r ;
}tree[210000] ;
void up( int i ) {
tree[i].a = tree[i*2].a * tree[i*2+1].a ;
}
matrix find( int i , int l , int r ) {
if ( tree[i].l == l && tree[i].r == r ) return tree[i].a ;
int mid = ( tree[i].l + tree[i].r ) / 2 ;
if ( r <= mid ) return find( i * 2 , l , r ) ;
else if ( l > mid ) return find( i * 2 + 1 , l , r ) ;
else return find( i * 2 , l , mid ) * find( i * 2 + 1 , mid + 1 , r ) ;
}
void maketree( int i , int l , int r ) {
tree[i].l = l ; tree[i].r = r ; tree[i].a.clrr() ;
if ( l == r ) {
repf( x , 0 , 1 )
repf( y , 0 , 1 )
scanf("%d" , &tree[i].a.a[x][y] ) ;
return ;
}
int mid = ( l + r ) / 2 ;
maketree( i * 2 , l , mid ) ;
maketree( i * 2 + 1 , mid + 1 , r ) ;
up(i) ;
}
int main(){
bool first = true ;
while ( scanf("%d %d %d" , &R , &n , &m ) == 3 ) {
if ( !first ) puts("" ) ;
maketree( 1 , 1 , n ) ;
repf( i , 1 , m ) {
int l , r ;
if ( i != 1 ) puts("") ;
scanf("%d %d" , &l , &r ) ;
if ( l > r ) swap( l , r ) ;
find( 1 , l , r ).show() ;
}
first = false ;
}
}
Problem C: Fibonacci Subsequence
有一个长度为3000的序列,问序列中的满足斐波拉契性质的序列最长是多少。
Solution
Tag:动态规划,数据结构
首先把数离散一下,这样我们就只有3000个数,dp[i][j]表示当前位置为i,上一个数为j的最长长度,枚举两个位置i个j,则dp[i][hash(a[j])]= max( dp[j][hash(a[i]-a[j])]+1)。这题会卡logn,所以hash手写或者用hash_map。
/*
* Author: chlxyd
* Created Time: 2013/7/19 16:54:11
* File Name: C (2).cpp
*/
#include<iostream>
#include<sstream>
#include<fstream>
#include<vector>
#include<list>
#include<deque>
#include<queue>
#include<stack>
#include<map>
#include<set>
#include<bitset>
#include<algorithm>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cctype>
#include<cmath>
#include<ctime>
#include <utility>
#include <ext/hash_map>
using namespace std;
using namespace __gnu_cxx;
const double eps(1e-8);
typedef long long lint;
#define clr(x) memset( x , 0 , sizeof(x) )
#define sz(v) ((int)(v).size())
#define rep(i, n) for (int i = 0; i < (n); ++i)
#define repf(i, a, b) for (int i = (a); i <= (b); ++i)
#define repd(i, a, b) for (int i = (a); i >= (b); --i)
#define clrs( x , y ) memset( x , y , sizeof(x) )
hash_map<int,int> mp ;
int n , top ;
int a[3100] ;
short int f[3010][3010] ;
int jlx , jly ;
int mod = 1000007 ;
bool bj[3100] ;
int flag[3010] ;
int hhash( int a ) {
if ( mp[a] )return mp[a] ;
return mp[a] = ++ top ;
}
int main(){
bool ff = true ;
while ( scanf("%d" , &n ) == 1 ) {
top = 0 ;
clr(bj) ;
mp.clear() ;
if (!ff) puts("") ;
repf( i , 1 , n )
repf( j , 1 , n ) f[i][j] = 0 ;
ff = false ;
repf( i , 1 , n ) {
scanf("%d" , &a[i] ) ;
hhash(a[i]) ;
}
if ( n == 1 ) {
printf("1\n") ;
printf("%d\n" , a[1] ) ;
continue ;
}
int ans = 0 ;
repf( j , 1 , n ) flag[j] = hhash(a[j]) ;
repf( i , 1 , n ) {
repf( j , 1 , i - 1 ) {
int p = flag[j] ;
f[i][p] = max( f[i][p] , (short int)2 ) ;
hash_map<int,int>::iterator tmp = mp.find(a[i] - a[j]);
if ( tmp == mp.end() )
continue ;
int k = tmp->second ;
if ( f[i][p] - f[j][k] - 1 < 0 )
f[i][p] = f[j][k] + 1 ;
if ( ans < f[i][p] ) {
ans = f[i][p] ;
jlx = i ; jly = j ;
}
}
}
if ( ans == 0 ) {
ans = 2 ;
jlx = 1 ;
jly = 2 ;
}
bj[jlx] = true ; bj[jly] = true ;
printf("%d\n" , ans ) ;
repd( i , jly - 1 , 1 ) {
if ( a[i] == a[jlx] - a[jly] ) {
bj[i] = true ;
jlx = jly ;
jly = i ;
}
}
bool first = true ;
repf( i , 1 , n ) {
if ( bj[i] ) {
if ( !first ) printf(" ") ;
first = false ;
printf("%d" , a[i] ) ;
}
}
printf("\n") ;
}
}
Problem D: Hexagon and Rhombic Dominoes
给一个边长为n正六边形,用三角形划分了,问用题中给的方块去铺,有多少种铺满方式。
Solution
Tag:动态规划
盗个watashi blog的图。
图中可以很清楚的看出,如果按照列来分的话,行的状态是非常清楚的,然后按照这个状态表示来进行转移就行了,到了中间的位置对于当前方案数在另外一边也一定能达到这么多方案,所以答案累加方案数的平方。然后打表什么的随便写了。
附做表程序
/*
#include<iostream>
#include<sstream>
#include<fstream>
#include<vector>
#include<list>
#include<deque>
#include<queue>
#include<stack>
#include<map>
#include<set>
#include<bitset>
#include<algorithm>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cctype>
#include<cmath>
#include<ctime>
using namespace std;
const double eps(1e-8);
typedef long long lint;
#define clr(x) memset( x , 0 , sizeof(x) )
#define sz(v) ((int)(v).size())
#define rep(i, n) for (long long i = 0; i < (n); ++i)
#define repf(i, a, b) for (long long i = (a); i <= (b); ++i)
#define repd(i, a, b) for (long long i = (a); i >= (b); --i)
#define clrs( x , y ) memset( x , y , sizeof(x) )
long long top ;
long long n ;
long long dp[20][1<<20] ;
long long jl[20][2] ;
void dfs( long long i , long long s , long long val , long long ii ) {
if ( i == top + 1 ) {
dp[ii][s] += val ;
return ;
}
repf( j , jl[i][0] , jl[i][1] ) {
dfs( i + 1 , s + ( 1 << j ) , val , ii ) ;
}
}
int main(){
scanf("%lld" , &n );
rep( i , n + 1 ) dp[n+1][1<<i] = 1 ;
repf( i , n + 2 , n + n ) {
rep( j , 1 << i ) {
long long s = j ;
if ( dp[i-1][s] == 0 ) continue ;
s <<= 1 ;
long long num = i - n - 1 ;
top = 0 ;
long long last = 0 ;
rep( k , i ) {
if ( s & ( 1 << k ) ) {
jl[++top][0] = last ;
jl[top][1] = k - 1 ;
last = k ;
}
}
jl[++top][0] = last ;
jl[top][1] = i - 1 ;
dfs( 1 , 0 , dp[i-1][j] , i ) ;
}
}
long long ans = 0 ;
rep( j , 1 <<(n+n) ) {
ans += dp[n+n][j] * dp[n+n][j] ;
}
cout<<ans<<endl;
}
*/
/*
* Author: chlxyd
* Created Time: 2013/7/19 20:21:36
* File Name: D1.cpp
*/
#include<iostream>
#include<sstream>
#include<fstream>
#include<vector>
#include<list>
#include<deque>
#include<queue>
#include<stack>
#include<map>
#include<set>
#include<bitset>
#include<algorithm>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cctype>
#include<cmath>
#include<ctime>
using namespace std;
const double eps(1e-8);
typedef long long lint;
#define clr(x) memset( x , 0 , sizeof(x) )
#define sz(v) ((int)(v).size())
#define rep(i, n) for (int i = 0; i < (n); ++i)
#define repf(i, a, b) for (int i = (a); i <= (b); ++i)
#define repd(i, a, b) for (int i = (a); i >= (b); --i)
#define clrs( x , y ) memset( x , y , sizeof(x) )
long long f[80];
int main(){
f[1] = 2;
f[2] = 20;
f[3] = 980;
f[4] = 232848;
f[5] = 267227532;
f[6] = 1478619421136;
f[7] = 39405996318420160;
bool first = true ;
int n ;
while ( scanf("%d" , &n ) == 1 ) {
if ( !first ) puts("") ;
first = false ;
printf("%lld\n" , f[n] ) ;
}
}
Problem E: Strange Limit
求f(a) = a^f(a) mod m!的值
Solution
Tag:数学
M的阶层和a为质数都是无用的东西。
欧拉定理的内容是:如果a和n互质,那么aφ(n)=1(modn);对于任意a, n和较大的b,有ab=aφ(n)+b mod φ(n)(mod n)。
设b = m!,那么对于(a^f(a)) % b,套进公式则等于a^(φ(b) + b mod φ(b))mod b, 而a^b mod φ(b) 同样套入公式等于a^(φ(φ(b) )+ b modφ(φ(b))) modφ(b), 就这一直递归下去φ(φ(φ.. φ(b)…))最终会等于1.
这样就可以递归求解了。
/*
* Author: chlxyd
* Created Time: 2013/7/19 15:50:31
* File Name: E.cpp
*/
#include<iostream>
#include<sstream>
#include<fstream>
#include<vector>
#include<list>
#include<deque>
#include<queue>
#include<stack>
#include<map>
#include<set>
#include<bitset>
#include<algorithm>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cctype>
#include<cmath>
#include<ctime>
using namespace std;
const double eps(1e-8);
typedef long long lint;
#define clr(x) memset( x , 0 , sizeof(x) )
#define sz(v) ((int)(v).size())
#define rep(i, n) for (lint i = 0; i < (n); ++i)
#define repf(i, a, b) for (lint i = (a); i <= (b); ++i)
#define repd(i, a, b) for (lint i = (a); i >= (b); --i)
#define clrs( x , y ) memset( x , y , sizeof(x) )
lint n, m, mod;
lint mypow(lint a, lint b, bool &flag) {
lint res = 1;
while (b != 0) {
if (b % 2 == 1) {
res *= a;
if (res >= mod)
flag = true;
res %= mod;
}
a *= a;
if (a >= mod) flag = true;
a %= mod;
b >>= 1;
}
return res;
}
int main(){
bool first = false;
while (scanf("%lld%lld", &n, &m) == 2) {
if (first) printf("\n");
if (n == 2 && m == 2) {
printf("0\n");
first = true;
continue;
}
mod = 1;
repf (i, 1, m)
mod *= i;
bool flag = false;
lint ans = 1;
int h = 200;
while (--h > 0) {
ans = mypow(n, ans, flag);
}
printf("%lld\n", ans);
first = true;
}
return 0;
}
Problem F: Little Mammoth
求圆与长方形的面积交
Solution
Tag:计算几何
可以用几何中求多边形面积的方法来求,求出所有圆与长方形形的交点,然后算出三角或者扇形的有向面积,相加求绝对值即可。
这个watashi博客中的图很直观。
这里有求线段与圆的交点的介绍:http://www.thecodeway.com/blog/?p=1873
/*
* Author: xioumu
* Created Time: 2013/7/21 15:24:58
* File Name: F.cpp
* solve: F.cpp
*/
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<algorithm>
#include<string>
#include<map>
#include<set>
#include<iostream>
#include<vector>
#include<queue>
using namespace std;
#define sz(v) ((int)(v).size())
#define rep(i, n) for (int i = 0; i < (n); ++i)
#define repf(i, a, b) for (int i = (a); i <= (b); ++i)
#define repd(i, a, b) for (int i = (a); i >= (b); --i)
#define clr(x) memset(x,0,sizeof(x))
#define clrs( x , y ) memset(x,y,sizeof(x))
#define out(x) printf(#x" %d\n", x)
#define sqr(x) ((x) * (x))
typedef long long lint;
const int maxint = -1u>>1;
const double pi = acos(-1.0);
const double eps = 1e-8;
int sgn(const double &x) { return (x > eps) - (x < -eps); }
struct point {
double x, y;
point (double _x = 0, double _y = 0) : x(_x), y(_y) {
}
double operator * (const point &p) const {
return (x * p.y) - (y * p.x);
}
point operator - (const point &p) const {
return point(x - p.x, y - p.y);
}
point operator + (const point &p) const {
return point(x + p.x, y + p.y);
}
void output() {
printf("%.3f %.3f\n", x, y);
}
};
point operator * (const double &l, const point &p) {
return point(l * p.x, l * p.y);
}
vector<point> p;
void gao(point u, point v, double r) {
double a = sqr(v.x - u.x) + sqr(v.y - u.y);
double b = 2 * ((v.x - u.x) * u.x + (v.y - u.y) * u.y);
double c = sqr(u.x) + sqr(u.y) - sqr(r);
double det = b * b - 4 * a * c;
p.push_back(u);
if (det < 0) {
return;
}
double t1 = (-b + sqrt(det)) / 2 / a;
double t2 = (-b - sqrt(det)) / 2 / a;
//printf("%f %f\n", t1, t2);
if (t1 > t2)
swap(t1, t2);
if (sgn(t1) > 0 && sgn(t1 - 1) < 0) {
p.push_back(u + t1 * (v - u));
}
if (sgn(t2) > 0 && sgn(t2 - 1) < 0 && sgn(t1 - t2) != 0) {
p.push_back(u + t2 * (v - u));
}
}
double tri(point a, point b) {
return abs( (a * b) / 2 );
}
double sec(point a, point b, double r) {
double ang1 = atan2(a.y, a.x);
double ang2 = atan2(b.y, b.x);
if (ang1 < 0) ang1 = 2 * pi + ang1;
if (ang2 < 0) ang2 = 2 * pi + ang2;
double dang = abs(ang2 - ang1);
if (dang > pi)
dang = 2 * pi - dang;
return r * r * dang / 2;
}
//double sec(const point& u, const point& v, double r) {
//double t = atan2(v.y, v.x) - atan2(u.y, u.x);
//while (t > pi) { // WA!!
//t -= 2 * pi;
//}
//while (t < -pi) {
//t += 2 * pi;
//}
//return abs(r * r * t) / 2;
//}
int main() {
bool blank = false;
double x, y, r, x1, y1, x2, y2;
while (scanf("%lf%lf%lf", &x, &y, &r) == 3) {
if (blank) puts("");
blank = 1;
scanf("%lf%lf%lf%lf", &x1, &y1, &x2, &y2);
x1 -= x;
y1 -= y;
x2 -= x;
y2 -= y;
p.clear();
gao(point(x1, y1), point(x1, y2), r);
gao(point(x1, y2), point(x2, y2), r);
gao(point(x2, y2), point(x2, y1), r);
gao(point(x2, y1), point(x1, y1), r);
double ans = 0;
p.push_back(p.front());
rep (i, sz(p) - 1) {
if (sgn( hypot((p[i].x + p[i + 1].x) / 2, (p[i].y + p[i + 1].y) / 2) - r) >= 0) {
ans += sgn(p[i] * p[i + 1]) * sec(p[i], p[i + 1], r);
//printf("sec : %f\n", sgn(p[i] * p[i + 1]) * sec(p[i], p[i + 1], r));
}
else {
ans += sgn(p[i] * p[i + 1]) * tri(p[i], p[i + 1]);
//printf("tri : %f\n", sgn(p[i] * p[i + 1]) * tri(p[i], p[i + 1]));
}
//p[i].output();
}
printf("%.11f\n", abs(ans));
}
return 0;
}
Problem G: Network Wars
给一个图,让你选择一些边,使得这些边是用最小的代价使得起点与终点分开。代价的定义是选择的边的权值和除以边数
Solution
Tag:网络流,分数规划
二分答案,求最小割,对于每一次二分,假设答案为x,把所有的边减去x,若边权小于0,加入割边只会减小答案的值,所以一定在割边中。对剩下的边,求最小割,若所有割边(包括权值小于0的边)的权值和小于0,则x还可以更小,否则x需要更大。具体的分数规划的证明在 胡伯涛的《最小割模型在信息学竞赛中的应用》有证明。
注意,这里的最小割需要用实数来求。
/*
* Author: xioumu
* Created Time: 2013/7/20 23:09:25
* File Name: F_xioumu.cpp
* solve: F_xioumu.cpp
*/
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<algorithm>
#include<string>
#include<map>
#include<set>
#include<iostream>
#include<vector>
#include<queue>
using namespace std;
#define sz(v) ((int)(v).size())
#define rep(i, n) for (int i = 0; i < (n); ++i)
#define repf(i, a, b) for (int i = (a); i <= (b); ++i)
#define repd(i, a, b) for (int i = (a); i >= (b); --i)
#define clr(x) memset(x,0,sizeof(x))
#define clrs( x , y ) memset(x,y,sizeof(x))
#define out(x) printf(#x" %d\n", x)
#define sqr(x) ((x) * (x))
typedef long long lint;
const int maxint = -1u>>1;
const double eps = 1e-8;
const int maxn = 400 + 10;
int sgn(const double &x) { return (x > eps) - (x < -eps); }
struct Graph {
struct Adj {
int v, b, id;
double c;
Adj(int _v, double _c, int _id, int _b) :
v(_v), c(_c), id(_id), b(_b){}
Adj(){}
};
int n, S, T, h[maxn], cnt[maxn];
vector<Adj> adj[maxn];
void clear() {
for (int i = 0; i < n; i++) {
adj[i].clear();
}
n = 0;
}
void insert(int u, int v, double c, int id, int d = 0) {
n = max(n, max(u, v) + 1);
adj[u].push_back(Adj(v, c, id, adj[v].size()));
adj[v].push_back(Adj(u, c * d, id, adj[u].size() - 1));
}
double maxflow(int _S, int _T) {
S = _S, T = _T;
fill(h, h + n, 0);
fill(cnt, cnt + n, 0);
double flow = 0;
while (h[S] < n) {
flow += dfs(S, maxint);
}
return flow;
}
double dfs(int u, double flow) {
if (u == T) {
return flow;
}
int minh = n - 1;
double ct = 0;
for (vector<Adj>::iterator it = adj[u].begin(); sgn(flow) > 0 && it != adj[u].end(); ++it) {
if (sgn(it->c) > 0) {
if (h[it->v] + 1 == h[u]) {
double k = dfs(it->v, min(it->c, flow));
if (sgn(k) > 0) {
it->c -= k;
adj[it->v][it->b].c += k;
flow -= k;
ct += k;
}
if (h[S] >= n) {
return ct;
}
}
minh = min(minh, h[it->v]);
}
}
if (sgn(ct) > 0) {
return ct;
}
if (--cnt[h[u]] == 0) {
h[S] = n;
}
h[u] = minh + 1;
++cnt[h[u]];
return 0;
}
}G, G2;
int n, m;
int S, T;
bool gao(double x) {
double sum = 0;
G2 = G;
rep (i, n) {
rep (k, sz(G2.adj[i])) {
G2.adj[i][k].c -= x;
if (sgn(G2.adj[i][k].c) < 0) {
sum -= G2.adj[i][k].c;
G2.adj[i][k].c = 0;
}
}
}
sum /= 2;
double ans = G2.maxflow(S, T);
ans -= sum;
if (sgn(ans) <= 0) return true;
else return false;
}
vector<int> ans;
int v[maxn], va[maxn];
void dfs(int w) {
if (v[w]) return;
v[w] = 1;
rep (i, sz(G2.adj[w])) {
int j = G2.adj[w][i].v;
if (sgn(G2.adj[w][i].c) > 0) {
dfs(j);
}
}
}
void mark_ans(double mans) {
memset(v, 0, sizeof(v));
dfs(S);
ans.clear();
memset(va, 0, sizeof(va));
rep (i, n) {
//if (v[i] == 0) continue;
rep (k, sz(G.adj[i])) {
int j = G.adj[i][k].v;
//printf("%d %d %.2f %d %d\n", i, j, G2.adj[i][k].c, v[i], v[j]);
if (va[G.adj[i][k].id]) continue;
if ((v[i] == 1 && v[j] == 0) || sgn(G.adj[i][k].c - mans) < 0) {
ans.push_back(G.adj[i][k].id);
va[G.adj[i][k].id] = 1;
}
}
}
}
int main() {
bool blank = false;
while (scanf("%d%d", &n, &m) == 2) {
if (blank) puts("");
blank = true;
G.clear();
double l = 0, r = 0;
rep (i, m) {
int x, y, z;
scanf("%d%d%d", &x, &y, &z);
x--, y--;
G.insert(x, y, z, i + 1, 1);
r += z;
}
double mans = r;
S = 0, T = n - 1;
rep (i, 100) {
double mid = (l + r) / 2.0;
//printf("%f %f\n", l, r);
if (gao(mid)) {
r = mid;
mans = mid;
}
else l = mid;
}
//out("test");
gao(mans);
mark_ans(mans);
printf("%d\n", sz(ans));
rep (i, sz(ans)) {
if (i != 0) printf(" ");
printf("%d", ans[i]);
}
printf("\n");
//printf("%f\n", mans);
}
return 0;
}
Problem H: Oil Deal
给一个图,让你选择一些边删了,要求删除后的图要是连通图。删边有各种的代价,求在一定代价下最多能删多少边。
Solution
Tag:贪心,最小生成树
求最大生成树,除了这个生成树里的边都是可以删的。于是乎把剩下的边排序从代价小的取,能取多少取多少即可。
证明:假设取了最大生成树里的边A后更优,代替A的放进生成树中的边B一定比边A代价高。但这样的话B会比A优先选进最大生成树中,所以矛盾。
/*
* Author: chlxyd
* Created Time: 2013/7/19 14:17:32
* File Name: H.cpp
*/
#include<iostream>
#include<sstream>
#include<fstream>
#include<vector>
#include<list>
#include<deque>
#include<queue>
#include<stack>
#include<map>
#include<set>
#include<bitset>
#include<algorithm>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cctype>
#include<cmath>
#include<ctime>
using namespace std;
const double eps(1e-8);
typedef long long lint;
#define clr(x) memset( x , 0 , sizeof(x) )
#define sz(v) ((lint)(v).size())
#define rep(i, n) for (lint i = 0; i < (n); ++i)
#define repf(i, a, b) for (lint i = (a); i <= (b); ++i)
#define repd(i, a, b) for (lint i = (a); i >= (b); --i)
#define clrs( x , y ) memset( x , y , sizeof(x) )
const lint maxn = 100000 * 2 + 10;
struct node {
lint x, y, z, id;
node (const lint _x = 0, const lint _y = 0, const lint _z = 0, const lint _id = 0) :
x(_x), y(_y), z(_z), id(_id){
}
};
vector<node> e, can;
vector<lint > pans;
lint fa[maxn], n, m, sum;
lint find(lint w) {
if (fa[w] == w) return w;
lint k = find(fa[w]);
fa[w] = k;
return k;
}
bool cmp(const node &a, const node &b) {
return a.z > b.z;
}
bool cmp2(const node &a, const node &b) {
return a.z < b.z;
}
int main(){
bool flag = false;
while (scanf("%lld%lld%lld", &n, &m, &sum) == 3) {
if (flag) printf("\n");
e.clear();
can.clear();
rep (i, m) {
lint x, y, z;
scanf("%lld%lld%lld", &x, &y, &z);
x--, y--;
e.push_back(node(x, y, z, i + 1));
}
sort(e.begin(), e.end(), cmp);
rep (i, n)
fa[i] = i;
rep (i, m) {
lint r = find(e[i].x);
lint w = find(e[i].y);
if (r != w) {
fa[r] = w;
}
else {
can.push_back(e[i]);
}
}
sort(can.begin(), can.end(), cmp2);
pans.clear();
rep (i, sz(can)) {
if (sum < can[i].z) break;
pans.push_back(can[i].id);
sum -= can[i].z;
}
printf("%lld\n", sz(pans));
rep (i, sz(pans)) {
if (i != 0) printf(" ");
printf("%lld", pans[i]);
}
if (sz(pans) != 0)
printf("\n");
flag = true;
}
return 0;
}
Problem I: Bishops on aToral Board
有一个n*m的棋盘,棋盘边缘是循环的,棋子可以往一个方向斜着走任意步。
Solution
Tag:贪心,最小生成树
答案就是gcd(n,m)。
囧,还不会证明。
/*
* Author: chlxyd
* Created Time: 2013/7/19 13:18:32
* File Name: I.cpp
*/
#include<iostream>
#include<sstream>
#include<fstream>
#include<vector>
#include<list>
#include<deque>
#include<queue>
#include<stack>
#include<map>
#include<set>
#include<bitset>
#include<algorithm>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cctype>
#include<cmath>
#include<ctime>
using namespace std;
const double eps(1e-8);
typedef long long lint;
#define clr(x) memset( x , 0 , sizeof(x) )
#define sz(v) ((int)(v).size())
#define rep(i, n) for (int i = 0; i < (n); ++i)
#define repf(i, a, b) for (int i = (a); i <= (b); ++i)
#define repd(i, a, b) for (int i = (a); i >= (b); --i)
#define clrs( x , y ) memset( x , y , sizeof(x) )
const int maxn = 100000 + 10;
char s1[maxn], s2[maxn];
int main(){
bool flag = false;
while (scanf("%s%s", s1, s2) == 2) {
if (flag) printf("\n");
//printf("%s\n%s\n", s1, s2);
int l1 = strlen(s1);
int l2 = strlen(s2);
int d1 = s1[l1 - 1] - '0';
int d2 = s2[l2 - 1] - '0';
if ((l1 == 1 && d1 == 0) || (l2 == 1 && d2 == 0))
printf("0\n");
else if (d1 % 2 == 0 && d2 % 2 == 0) {
printf("2\n");
}
else printf("1\n");
flag = true;
}
return 0;
}