这场状态不对劲,打的很差,该出的题都没看(莫名卡水题),sb博弈的表也能打错。A题打表也用太久时间,自己的板子都是错的(全世界找板子),还被题目吓住(钦定看不懂就是神题)。队内合作方式有点问题。
HDU5793
这是个打表很快就能发现等比性质的题。但是赛上我写了个矩阵快速幂(真不知道当时怎么想的)。。。
这个题就递推比较劲,此处解释下。
要求 ∑0≤k1,k2,...,km≤n∏1≤j<mCkjkj+1% 1000000007
很显然必须满足 0≤k1≤k2≤...≤km≤n 才对答案有贡献,其他情况都是0。
∑0≤k1≤k2≤...≤km≤n∏1≤j<mCkjkj+1% 1000000007
∑0≤km≤n(∑0≤km−1≤kmCkm−1km(∑...∑0≤k1≤k2Ck1k2))
∑0≤km≤n(∑0≤km−1≤kmCkm−1km(∑...∑0≤k2≤k3Ck2k3∗2k2))
上面 ∑0≤k2≤k3Ck2k3∗2k2 由二项式 (2+1)k3 展开得到
一步一步合并回去就是 ∑0≤km≤nmkm 等比数列遍得到了。
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define ALL(x) x.begin(), x.end()
#define INS(x) inserter(x, x,begin())
#define ll long long
#define CLR(x) memset(x, 0, sizeof x)
using namespace std;
const int inf = 0x3f3f3f3f;
const ll MOD = 1e9 + 7;
const int maxn = 1e6 + 10;
const int maxv = 1e3 + 10;
const double eps = 1e-9;
ll Pow(ll a, ll n) {
ll ret = 1;
a %= MOD;
while(n) {
if(n & 1) ret = ret * a % MOD;
a = a * a % MOD;
n >>= 1;
}
return ret;
}
int main() {
#ifdef LOCAL
freopen("C:\\Users\\Administrator\\Desktop\\in.txt", "r", stdin);
#endif
int T;
scanf("%d", &T);
ll n, m;
while(T--) {
scanf("%lld%lld", &n, &m);
ll ans = Pow(m, n+1) - 1;
ans = (ans + MOD) % MOD;
ans = ans * Pow(m - 1, MOD - 2) % MOD;
printf("%lld\n", ans);
}
return 0;
}
HDU5794
n(n≤1e18)∗m(m≤1e18) 的格子有 r 个坏点,问你有多少种方案像马一样从 (1,1) 跳到 (n,m) 。每次横坐标和纵坐标只能递增。
这题可以先想想数据范围小的时候我们怎么搞。就是一种像组合数的 dp 。打个表可以发现,整个图有值的地方是斜着的杨辉三角,可以通过坐标计算出当前点 (x,y) 对应的杨辉三角的位置,然后用 lucas 定理算组合数,再去重。用容斥去重,考虑 ans[i] 最后走到的坏点是 i ,从 i 到终点的方案数。对坐标的点进行排序,倒着遍历坏点,比 i 大的点都是求出来了的。那么从 i 出发到终点的且不经过其他任何坏点的方案数就等于直接从 i 出发到终点的方案数减去在 i 之后的点 j 到终点的方案数乘 i到j 的方案数,即减去 ans[j]∗calc(i−>j) 。最后算出从起点到终点的方案数,枚举坏点,减去以每个坏点结尾的方案数就是最后答案。注意!不能以0判断当前点是否有用!!!因为 mod 很小,大数据可以使得方案数 %mod 为0
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define ALL(x) x.begin(), x.end()
#define INS(x) inserter(x, x,begin())
#define ll long long
#define CLR(x) memset(x, 0, sizeof x)
#define fi first
#define se second
using namespace std;
const int inf = 0x3f3f3f3f;
const ll MOD = 110119;
const int maxn = 1e6 + 10;
const int maxv = 1e3 + 10;
const double eps = 1e-9;
ll F[MOD + 10];
void init(ll p) {
F[0] = 1;
for(ll i = 1; i <= p; i++) {
F[i] = F[i-1] * i % MOD;
}
}
ll inv(ll a, ll m) {
if(a == 1) return 1;
return inv(m % a, m) * (m - m / a) % m;
}
ll lucas(ll n, ll m, ll p) {
ll ans = 1;
while(n && m) {
ll a = n % p;
ll b = m % p;
if(a < b) return 0;
ans = ans * F[a] % p * inv(F[b] * F[a-b] % p, p) % p;
n /= p;
m /= p;
}
return ans;
}
typedef pair sta;
sta get(ll n, ll m) {
sta tmp;
tmp.fi = (n + m + 1) / 3 - 1;
tmp.se = m - tmp.fi - 1;
return tmp;
}
ll calc(ll n, ll m) {
if((n + m + 1) % 3) return 0;
sta ret = get(n, m);
if(ret.se < 0 || ret.se > ret.fi) return 0;
return lucas(ret.fi, ret.se, MOD);
}
ll ans[maxv];
int main() {
#ifdef LOCAL
freopen("C:\\Users\\Administrator\\Desktop\\in.txt", "r", stdin);
freopen("C:\\Users\\Administrator\\Desktop\\out.txt","w",stdout);
#endif
ll n, m, r;
init(MOD);
int cas = 0;
while(scanf("%lld%lld%lld", &n, &m, &r) != EOF) {
std::vector pos;
printf("Case #%d: ", ++cas);
for(int i = 0; i < r; i++) {
ll x, y;
scanf("%lld%lld", &x, &y);
if(calc(x, y) < 0) continue;
pos.push_back(sta(x, y));
}
sort(ALL(pos));
ll res = calc(n, m);
for(int i = pos.size() - 1; ~i; i--) {
ans[i] = calc(n-pos[i].fi+1, m-pos[i].se+1);
for(int j = i + 1; j < pos.size(); j++) {
if(pos[j].se < pos[i].se) continue;
ans[i] = (ans[i] - ans[j] * calc(pos[j].fi-pos[i].fi+1, pos[j].se-pos[i].se+1) % MOD + MOD) % MOD;
}
res = (res - ans[i] * calc(pos[i].fi, pos[i].se) % MOD + MOD) % MOD;
}
printf("%lld\n", res);
}
return 0;
}
HDU5795
打表可以很容易的发现 %8 的规律
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define ALL(x) x.begin(), x.end()
#define INS(x) inserter(x, x,begin())
#define ll long long
#define CLR(x) memset(x, 0, sizeof x)
using namespace std;
const int inf = 0x3f3f3f3f;
const int MOD = 1e9 + 7;
const int maxn = 1e6 + 10;
const int maxv = 1e3 + 10;
const double eps = 1e-9;
int main() {
#ifdef LOCAL
freopen("C:\\Users\\Administrator\\Desktop\\in.txt", "r", stdin);
#endif
int T;
scanf("%d", &T);
while(T--) {
int n;
scanf("%d", &n);
int ans = 0;
for(int i = 1; i <= n; i++) {
int x;
scanf("%d", &x);
if(x % 8 == 0) {
x--;
}
else if((x + 1) % 8 == 0) {
x++;
}
ans ^= x;
}
if(ans) puts("First player wins.");
else puts("Second player wins.");
}
return 0;
}
HDU5798
这题很劲。
看到 xor 第一反应就是拆位来做。因为有 abs ,根本无法统一处理,不统一一定超时,因此必须拆开。考虑某位 cur 对于答案的贡献,若前一个与后一个数此位相同,那么无论是否异或,答案都是不改变。再仔细想想只有两个数的情况,设最高不同位为 hig (全同为0)设大的数为 a 小的数为 b ,那么比 hig 位小的位 j 对答案的贡献都是 a 的 j 位减去 b 的 j 位,当然若我们这位被异或了,那么更小的 j 位贡献全部反掉。当然,若 j 位也被异或了,那么又翻转了回来。因此只需要看到底此位被异或多少次就行了。推广到多个数的情况就行了。
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define ALL(x) x.begin(), x.end()
#define INS(x) inserter(x, x,begin())
#define ll long long
#define CLR(x) memset(x, 0, sizeof x)
using namespace std;
const ll inf = 0x3f3f3f3f3f3f3f3f;
const int MOD = 1e9 + 7;
const int maxn = 1e6 + 10;
const int maxv = 1e3 + 10;
const double eps = 1e-9;
ll arr[22][22];
int dep;
ll ansl, ansr;
int digit[22];
void dfs(int pos, ll sum) {
if(pos == dep) {
ll res = 0;
for(int i = 0; i < pos; i++) {
res |= digit[i] << i;
}
if(sum < ansr) {
ansr = sum;
ansl = res;
}
else if(sum == ansr) ansl = min(ansl, res);
return;
}
for(digit[pos] = 0; digit[pos] < 2; digit[pos]++) {
ll nsum = sum + arr[pos][pos];
for(int j = 0; j < pos; j++) {
if(digit[j] ^ digit[pos]) nsum -= arr[pos][j];
else nsum += arr[pos][j];
}
dfs(pos + 1, nsum);
}
}
int main() {
#ifdef LOCAL
freopen("C:\\Users\\Administrator\\Desktop\\in.txt", "r", stdin);
freopen("C:\\Users\\Administrator\\Desktop\\out.txt","w",stdout);
#endif
int T;
scanf("%d", &T);
while(T--) {
CLR(arr);
int n;
scanf("%d", &n);
int x; scanf("%d", &x);
for(int i = 1; i < n; i++) {
int y;
scanf("%d", &y);
int hig = 19;
while(hig >= 0 && ~(x ^ y) >> hig & 1) hig--;
int big = max(x, y);
int small = min(x, y);
for(int j = hig; ~j; j--) {
arr[hig][j] += (big >> j & 1) - (small >> j & 1);
}
swap(x, y);
}
dep = 20;
while(dep > 0 && !arr[dep-1][dep-1]) dep--;
for(int i = 0; i <= dep; i++) {
for(int j = 0; j <= i; j++) {
arr[i][j] <<= j;
}
}
ansl = ansr = inf;
dfs(0, 0);
printf("%lld %lld\n", ansl, ansr);
}
return 0;
}
HDU 5780
水dp
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define ALL(x) x.begin(), x.end()
#define INS(x) inserter(x, x,begin())
#define ll long long
#define CLR(x) memset(x, 0, sizeof x)
using namespace std;
const int inf = 0x3f3f3f3f;
const int MOD = 1e9 + 7;
const int maxn = 1e6 + 10;
const int maxv = 1e3 + 10;
const double eps = 1e-9;
int a[maxv];
ll dp[2][maxv][3][3];
int main() {
#ifdef LOCAL
freopen("C:\\Users\\Administrator\\Desktop\\in.txt", "r", stdin);
freopen("C:\\Users\\Administrator\\Desktop\\out.txt","w",stdout);
#endif
int T;
scanf("%d", &T);
while(T--) {
int n, s;
scanf("%d%d", &n, &s);
CLR(dp);
for(int i = 1; i <= n; i++) scanf("%d", a + i);
dp[0][0][0][0] = 1;
int cur = 0;
for(int i = 1; i <= n; i++) {
cur ^= 1;
for(int j = 0; j <= s; j++)
for(int k = 0; k <= 2; k++)
for(int l = 0; l <= 2; l++) {
dp[cur][j][k][l] = 0;
if(j >= a[i]) {
dp[cur][j][k][l] += dp[cur^1][j-a[i]][k][l];
if(k) dp[cur][j][k][l] += dp[cur^1][j-a[i]][k-1][l];
}
if(l) dp[cur][j][k][l] += dp[cur^1][j][k][l-1];
dp[cur][j][k][l] += dp[cur^1][j][k][l];
dp[cur][j][k][l] %= MOD;
}
}
ll ans = 0;
for(int i = 1; i <= s; i++) {
ans += dp[cur][i][2][2];
ans %= MOD;
}
printf("%lld\n", ans * 4 % MOD);
}
return 0;
}
HDU 5802
贪心,注意停顿和加取个max
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define ALL(x) x.begin(), x.end()
#define INS(x) inserter(x, x,begin())
#define ll long long
#define CLR(x) memset(x, 0, sizeof x)
using namespace std;
const int inf = 0x3f3f3f3f;
const int MOD = 1e9 + 7;
const int maxn = 1e6 + 10;
const int maxv = 1e3 + 10;
const double eps = 1e-9;
int main() {
#ifdef LOCAL
freopen("C:\\Users\\Administrator\\Desktop\\in.txt", "r", stdin);
freopen("C:\\Users\\Administrator\\Desktop\\out.txt","w",stdout);
#endif
int T;
scanf("%d", &T);
while(T--) {
int p, q;
scanf("%d%d", &p, &q);
if(p <= q) {
printf("%d\n", q - p);
continue;
}
p -= q;
int ans = inf;
int pause = 0;
int cur = 0;
while(p) {
if(p == 1) {
ans = min(ans, cur + pause + 1);
break;
}
int big = 32 - __builtin_clz(p);
int num = 1 << big;
num--;
ans = min(ans, cur + __builtin_popcount(num) + max(pause, min(q, num - p)));
pause++;
num >>= 1;
p -= num;
cur += __builtin_popcount(num);
}
printf("%d\n", ans);
}
return 0;
}
HDU5803
数位 dp ,很不错的学习题。。
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define ALL(x) x.begin(), x.end()
#define INS(x) inserter(x, x,begin())
#define ll long long
#define CLR(x) memset(x, 0, sizeof x)
using namespace std;
const int inf = 0x3f3f3f3f;
const int MOD = 1e9 + 7;
const int maxn = 1e6 + 10;
const int maxv = 1e3 + 10;
const double eps = 1e-9;
ll p[4];
int dp[66][20][5][5];
int val[3] = {-2, 0, 2};
inline int get(int num, int sub) {
if(num > 2) return 3;
sub += val[num];
if(abs(sub) <= 1) return sub + 1;
return sub > 0 ? 3 : -1;
}
int dfs(int pos, int mark, int first, int second) {
if(pos == -1) return first >= 2 && second >= 1;
int &ret = dp[pos][mark][first][second];
if(-1 != ret) return ret;
ret = 0;
int digit[4];
for(int i = 0; i < 4; i++) digit[i] = (mark >> i & 1) ? 1 : (p[i] >> pos & 1);
for(int i = 0; i <= digit[0]; i++) {
for(int j = 0; j <= digit[1]; j++) {
for(int k = 0; k <= digit[2]; k++) {
for(int l = 0; l <= digit[3]; l++) {
int newfirst = get(first, i + k - j - l);
int newsecond = get(second, i + l - j - k);
if(-1 == newfirst || -1 == newsecond) continue;
int newmark = mark;
if(i < digit[0]) newmark |= 1;
if(j < digit[1]) newmark |= 2;
if(k < digit[2]) newmark |= 4;
if(l < digit[3]) newmark |= 8;
ret = (ret + dfs(pos-1, newmark, newfirst, newsecond)) % MOD;
}
}
}
}
return ret;
}
int main() {
#ifdef LOCAL
freopen("C:\\Users\\Administrator\\Desktop\\in.txt", "r", stdin);
freopen("C:\\Users\\Administrator\\Desktop\\out.txt","w",stdout);
#endif
int T;
scanf("%d", &T);
while(T--) {
memset(dp, -1, sizeof dp);
for(int i = 0; i < 4; i++)
scanf("%lld", p + i);
printf("%d\n", dfs(61, 0, 1, 1));
}
return 0;
}