非常绝望的一次测试。早上状态很不好呀,t1卡了一个多小时没想出正解,后面就慌了。
以此博客纪念一下这次悲伤的考试。
t1 组合数问题
实际上就是杨辉三角做dp,先预处理出组合数,mod k防止爆掉,然后用相同的三角形结构更新dp值,dp[i][j]=dp[i-1][j]+dp[i][j-1]-dp[i-1][j-1],如果组合数mod k的值等于0,就++.
#include<iostream>
#include<cstdio>
using namespace std;
int yh[2005][2005], dp[2005][2005];
int main ( ) {
freopen ( "problem.in", "r", stdin );
freopen ( "problem.out", "w", stdout );
int t, k;
scanf ( "%d%d", &t, &k );
for ( int i = 0; i <= 2000; i ++ )
for ( int j = 0; j <= i; j ++ )
if ( j == 0 || j == i || i == 0 ) yh[i][j] = 1;
else yh[i][j] = (yh[i-1][j]+yh[i-1][j-1])%k;
for ( int i = 0; i <= 2000; i ++ )
for ( int j = 0; j <= 2000; j ++ ) {
dp[i][j] = dp[i-1][j] + dp[i][j-1] - dp[i-1][j-1];
if ( j > i ) continue;
if ( yh[i][j] == 0 ) dp[i][j] ++;
}
for ( int kk = 1; kk <= t; kk ++ ) {
int n, m;
scanf ( "%d%d", &n, &m );
printf ( "%d\n", dp[n][min(n,m)] );
}
}
t2 蚯蚓
三个不上升序列,第一个存原始蚯蚓长度,第二个存切后xq,第三个存x-xq,先sort一边q1,每次取三个队列队首切,切了后推入第二、三个队列,可以证明二三序列一定不上升。
但是q2、q3的h2、h3和h1不一样,h1存的是q1队首,h2、h3存q1、q2队首的前一项,因此判断队空是h2
#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
#define ll long long
const int N = 7000005;
ll q1[N], q2[N], q3[N], h1, h2, h3, t2, t3, t1;
bool cmp ( const ll &a, const ll &b ) {
return a > b;
}
int judge ( ) {
int ans = 0;
ll ma = -1301231123;
if ( h1 <= t1 ) ans = 1, ma = q1[h1];
if ( h2 < t2 && q2[h2+1] > ma) ans = 2, ma = q2[h2+1];
if ( h3 < t3 && q3[h3+1] > ma ) ans = 3, ma = q3[h3+1];//h2h3要加一
return ans;
}
int main ( ) {
freopen ( "earthworm.in", "r", stdin );
freopen ( "earthworm.out", "w", stdout );
int n, m, q, u, v, t;
scanf ( "%d%d%d%d%d%d", &n, &m, &q, &u, &v, &t );
for ( int i = 1; i <= n; i ++ )
scanf ( "%lld", &q1[i] );
sort ( q1+1, q1+1+n, cmp );
h1 = 1; t1 = n;
for ( int i = 1; i <= m; i ++ ) {
ll a;
int xx = judge ( );
if ( xx == 1 ) { a = q1[h1]; h1 ++; }
else if ( xx == 2 ) { a = q2[h2+1]; h2 ++; }
else if ( xx == 3 ) { a = q3[h3+1]; h3 ++; }
a = a + (i-1)*q;
if ( i % t == 0 ) printf ( "%lld ", a );
ll x = a*u/v; ll y = a-x;
q2[++t2] = x-i*q;
q3[++t3] = y-i*q;//相当于标记了每次切的蚯蚓
}
printf ( "\n" );
for ( int i = 1; i <= n+m; i ++ ) {
ll a;
int x = judge ( );
if ( x == 1 ) { a = q1[h1]; h1 ++; }
else if ( x == 2 ) { a = q2[h2+1]; h2 ++; }
else if ( x == 3 ) { a = q3[h3+1]; h3 ++; }
a = a + m*q;//最后一起加上理应加的总时间,如果被切过k次实际加上的是(m-k)*q.
if ( i % t == 0 ) printf ( "%lld ", a );
}
return 0;
}
t3 愤怒的小鸟
做过的一道状压dp!!可是还是爆零了!!!
有点小难受。。
先预处理出任意两点抛物线能打到的猪猪,状压存储。再遍历所有当前状态,更新加上能打到的猪猪后的状态。注意处理浮点数精度。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
using namespace std;
double x[20], y[20];
int dp[1<<18+1], f[20][20];
bool check ( int i, double a, double b ) {
double xx = x[i], yy = y[i];
if ( abs (xx * xx * a + xx * b - yy) < 1e-6 ) return true;
return false;
}
int main ( ) {
freopen ( "angrybirds.in", "r", stdin );
freopen ( "angrybirds.out", "w", stdout );
int T;
scanf ( "%d", &T );
while ( T-- ) {
int n, m;
memset ( dp, 0x3f3f3f3f, sizeof ( dp ) );
memset ( f, 0, sizeof ( f ) );
scanf ( "%d%d", &n, &m );
for ( int i = 1; i <= n; i ++ )
scanf ( "%lf%lf", &x[i], &y[i] );
for ( int i = 1; i <= n; i ++ )
for ( int j = 1; j <= n; j ++ ) {
double x1 = x[i], x2 = x[j], y1 = y[i], y2 = y[j];
double xx1 = x1*x1, xx2 = x2*x2;
double b = (y1*xx2-y2*xx1)/(x1*xx2-x2*xx1);
double a = (y1-b*x1)/xx1;
if ( a >= 0 ) continue;
for ( int k = 1; k <= n; k ++ )
if ( check ( k, a, b ) )
f[i][j] = f[i][j] | (1<<(k-1));
}
for ( int i = 1; i <= n; i ++ )
f[i][i] = 1<<(i-1);
dp[0] = 0;
for ( int i = 1; i <= n; i ++ )
for ( int j = 1; j <= n; j ++ )
for ( int s = 0; s < (1<<n); s ++ )
if ( dp[s|f[i][j]] > dp[s] + 1 )
dp[s|f[i][j]] = dp[s] + 1;
printf ( "%d\n", dp[(1<<n)-1] );
}
return 0;
}
可是有dalao用搜索搞出来了!!据说还比状压快!!%%%
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cmath>
#include <cstring>
#define mem(a, b) memset (a, b, sizeof(a))
#define dd double
using namespace std;
const int N = 45;
const dd pd = 1e-10;
int T, n, m, ans, q[N];
dd fc[N][2];
bool vis[N];
struct point {
dd x;
dd y;
}a[N];
const bool cmp (point aa, point bb) {
if (aa.x == bb.x) return aa.y < bb.y;
return aa.x < bb.x;
}
dd abss (dd a) {
if (a < 0) a = -a;
return a;
}
void dfs (int x, int num1, int num2, int use) {
if (x == n + 1) {
if (use < ans) ans = use;
return ;
}
if (use >= ans) return;
dd yy;
for (int i = 1; i <= num2; i++) {
yy = a[x].x * a[x].x * fc[i][0] + fc[i][1] * a[x].x;
if (abss(yy - a[x].y) <= pd) {
dfs (x + 1, num1, num2, use);
return ;
}
}
int now, nxt = num2 + 1;
dd xx, cc;
for (int i = 1; i <= num1; i++) {
if (vis[i]) continue;
now = q[i];
if (a[now].x == a[x].x) continue;
xx = a[now].x * a[now].x - a[now].x *a[x].x;
cc = a[now].y - a[x].y * a[now].x / a[x].x;
fc[nxt][0] = cc / xx;
if (fc[nxt][0] >= -pd) continue;
fc[nxt][1] = (a[now].y - fc[nxt][0] * a[now].x * a[now].x) / a[now].x;
vis[i] = 1;
dfs (x + 1, num1, nxt, use);
vis[i] = 0;
}
q[num1 + 1] = x;
vis[num1 + 1] = 0;
dfs (x + 1, num1 + 1, num2, use + 1);
}
int main () {
freopen ("angrybirds.in", "r", stdin);
freopen ("angrybirds.out", "w", stdout);
scanf ("%d", &T);
for (int U = 1; U <= T; U++) {
scanf ("%d%d", &n, &m);
for (int i = 1; i <= n; i++) {
scanf ("%lf%lf", &a[i].x, &a[i].y);
}
sort (a + 1, a + n + 1, cmp);
mem (vis, 0);
mem (fc, 0);
mem (q, 0);
q[1] = 1;
if (m != 1) ans = n;
else {
ans = n / 3;
if (n % 3 != 0) ans++;
ans++;
}
dfs (2, 1, 0, 1);
printf ("%d\n", ans);
}
return 0;
}
下个星期要翻身!!继续努力!!