A. The power of Fibonacci
正解是这样子的:
这个题目是某次翻Wikipedia的时候想到的
•https://en.wikipedia.org/wiki/Fibonomial_coefficient
•F[i]–F[i-1]–F[i-2]=0
•F[i]^2–2F[i-1]^2–2F[i-2]^2+F[i-3]=0
•F[i]^3–3F[i-1]^3–6F[i-2]^3+3F[i-3]+F[i-4]=0
•可以推广吗?可以的,就是FibonomialCoefficient
•通过简单的分析可以得到递推
•因为m的范围是1000,需要结合多项式取模
然而斐波那契数列模一个数是有循环的,找找循环节就完事了。
CODE
这是一份AC代码
#include <bits/stdc++.h>
using namespace std;
const int MAXN = 10000005;
const int md[2] = { 512, 1953125 };
int f[MAXN], ans[2], n, m;
inline int qpow(int a, int b, int c) {
int re = 1;
while(b) {
if(b&1) re = 1ll * re * a % c;
a = 1ll * a * a % c; b >>= 1;
}
return re;
}
int main () {
cin>>n>>m;
for(int k = 0, j; k < 2; ++k) {
f[0] = 0; f[1] = 1;
for(j = 2; ; ++j) {
f[j] = (f[j-1] + f[j-2]) % md[k];
if(f[j] == 0 && f[j-1] == 1) break; //1 = f[j+1] = f[j-1] + f[j](=0) = f[j-1]
}
for(int i = 0; i < j; ++i) {
int tim = n/j;
if(n%j >= i) ++tim;
ans[k] = (ans[k] + 1ll * qpow(f[i], m, md[0]*md[1]) * tim % md[k]) % md[k];
}
}
while(ans[1] % md[0] != ans[0]) ans[1] += md[1];
cout<<ans[1]<<endl;
}
然后我们把 qpow(f[i], m, md[0]*md[1]) 改成 qpow(f[i], m, md[k]) 它T了。
实际上是因为 md[0]*md[1] 是const int,快;而 md[k] 非也。
所以你把k=0和k=1分开写,分别写成qpow(f[i], m, md[0]) 和 qpow(f[i], m, md[1])也是能过的。
B.Quadratic equation
正解是这样子的:
•这个题目是某次翻Wikipedia的时候想到的
•https://en.wikipedia.org/wiki/Quadratic_residue
•解二次方程,核心在于求二次剩余(求平方根)
•如果p%4=3,x^2%p=a
•那么x=±pow(a,(p+1)/4,p)
•然后就和一般的方程一样解就可以了
•判断是否有解用
•https://en.wikipedia.org/wiki/Euler%27s_criterion
核心确实是求二次剩余。正解中用到了p%4=3的性质。
而我用到了p有原根的性质,转为指标然后BSGS。
实际上的任意模数二次剩余很麻烦的。。戳这里
myCODE
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int mod = 1e9 + 7;
int T, c, b;
inline int qpow(int a, int b) {
int re = 1;
while(b) {
if(b&1) re = 1ll * re * a % mod;
a = 1ll * a * a % mod; b >>= 1;
}
return re;
}
map<int, int>myhash;
inline int BSGS(int a, int b) {
myhash.clear(); int m = int(sqrt(mod) + 1);
int base = b;
for(int i = 0; i < m; ++i) {
myhash[base] = i;
base = 1ll * base * a % mod;
}
base = qpow(a, m); int tmp = 1;
for(int i = 1; i <= m+1; ++i) {
tmp = 1ll * tmp * base % mod;
if(myhash.count(tmp))
return i*m - myhash[tmp];
}
return -1;
}
inline int mysqrt(int x) {
if(!x) return 0;
int I = BSGS(5, x);
if(I&1) return -1;
return qpow(5, I/2);
}
int main(){
scanf("%d", &T);
while(T-->0) {
scanf("%d%d", &b, &c);
int A = (1ll * b * b % mod - 4ll * c % mod) % mod;
int B = mysqrt((A + mod) % mod);
if(B == -1) { puts("-1 -1"); continue; }
int y = 1ll * (b + B) * qpow(2, mod-2) % mod;
int x = (y - B + mod) % mod;
if(x > y) swap(x, y);
printf("%d %d
", x, y);
}
}
D.Knapsack Cryptosystem
水题,分两半暴力。
CODE
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
int n;
LL s, a[40];
map<LL,int>tmp;
int main(){
scanf("%d%lld", &n, &s);
for(int i = 0; i < n; ++i)
scanf("%lld", &a[i]);
int m = n/2;
for(int st = 0; st < (1<<m); ++st) {
LL sum = 0;
for(int i = 0; i < m; ++i)
if(st&(1<<i)) sum += a[i];
tmp[sum] = st;
}
tmp[0] = 0;
for(int st = 0; st < (1<<(n-m)); ++st) {
LL sum = 0;
for(int i = m; i < n; ++i)
if(st&(1<<(i-m))) sum += a[i];
if(tmp.count(s-sum)) {
int t = tmp[s-sum];
for(int i = 0; i < m; ++i)
putchar((t&(1<<i)) ? '1' : '0');
for(int i = m; i < n; ++i)
putchar((st&(1<<(i-m))) ? '1' : '0');
return 0;
}
}
}
E.All men are brothers
正解:
•核心就是每次合并考虑减少了多少。
•减少的数量等于合并的两个集合大小乘以,再乘以从其他集合中选出2个不在一个集合内的方案数
•从其他集合中选出2个不在一个集合内的方案数可以先计算任选2个的方案数,再减去来自同一个集合的方案数
貌似这是送分题,但是我不会。
CODE
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
inline int gi()
{
char c;int num=0,flg=1;
while((c=getchar())<'0'||c>'9')if(c=='-')flg=-1;
while(c>='0'&&c<='9'){num=num*10+c-48;c=getchar();}
return num*flg;
}
#define N 100005
#define LL unsigned long long
int fa[N],siz[N];
int find(int x){return x==fa[x]?x:fa[x]=find(fa[x]);}
int main()
{
int n,m,i,p,q;
LL pw=0;
n=gi();m=gi();
for(i=1;i<=n;i++){fa[i]=i;siz[i]=1;pw++;}
LL ans=1ll*n*(n-1)/2*(n-2)/3;
if(ans%4==0) ans=1ll*ans/4*(n-3);
else ans=1ll*(n-3)/4*ans;
printf("%llu
",ans);
for(i=1;i<=m;i++){
p=find(gi());q=find(gi());
if(p!=q){
pw-=(1ll*siz[p]*siz[p]+1ll*siz[q]*siz[q]);
ans-=1ll*siz[p]*siz[q]*((1ll*(n-siz[p]-siz[q])*(n-siz[p]-siz[q])-pw)/2);
fa[q]=p;
siz[p]+=siz[q];
pw+=1ll*siz[p]*siz[p];
}
printf("%llu
",ans);
}
}
H.Cutting Bamboos
二分+主席树 傻逼题
CODE
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
#define pLi pair<LL, int>
const int MAXN = 200005;
struct node {
int ls, rs;
LL val; int cnt;
}t[MAXN*50];
int n, q, rt[MAXN], tot, h[MAXN], c[MAXN];
inline bool cmp(int x, int y) { return h[x] > h[y]; }
inline void upd(int i) {
t[i].val = t[t[i].ls].val + t[t[i].rs].val;
t[i].cnt = t[t[i].ls].cnt + t[t[i].rs].cnt;
}
void modify(int &i, int l, int r, int x, int p) {
t[i = ++tot] = t[p];
if(l == r) { t[i].val = h[x]; t[i].cnt = 1; return; }
int mid = (l + r) >> 1;
if(x <= mid) modify(t[i].ls, l, mid, x, t[p].ls);
else modify(t[i].rs, mid+1, r, x, t[p].rs);
upd(i);
}
inline pLi add(pLi A, pLi B) {
return pLi(A.first + B.first, A.second + B.second);
}
pLi query(int i, int l, int r, int x, int y) {
if(!i) return pLi(0, 0);
if(x <= l && r <= y) return pLi(t[i].val, t[i].cnt);
int mid = (l + r) >> 1; pLi re = pLi(0, 0);
if(x <= mid) re = add(re, query(t[i].ls, l, mid, x, y));
if(y > mid) re = add(re, query(t[i].rs, mid+1, r, x, y));
return re;
}
int main () {
scanf("%d%d", &n, &q);
for(int i = 1; i <= n; ++i)
scanf("%d", &h[i]), c[i] = i;
sort(c + 1, c + n + 1, cmp);
rt[0] = 0;
for(int i = 1; i <= n; ++i)
modify(rt[i], 1, n, c[i], rt[i-1]);
for(int i = 1; i < n; ++i)
if(h[c[i]] == h[c[i+1]]) rt[i] = rt[i+1];
while(q-->0) {
int l, r, x, y;
scanf("%d%d%d%d", &l, &r, &x, &y);
double tmp = query(rt[n], 1, n, l, r).first;
tmp *= x; tmp /= y;
int L = 1, R = n, mid; pLi t;
while(L < R) {
mid = (L + R + 1) >> 1;
t = query(rt[mid], 1, n, l, r);
if(t.first - 1ll*t.second*h[c[mid]] <= tmp) L = mid;
else R = mid - 1;
}
t = query(rt[L], 1, n, l, r);
double S = t.first - 1ll*t.second*h[c[L]];
tmp -= S;
printf("%.6f
", h[c[L]] - tmp / t.second);
}
}
J. Symmetrical Painting
相当于多个公差为1的等差数列叠加,然后我写了个线段树被卡空间了。人没了。其实直接差分就行了。
CODE
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int MAXN = 300005;
const int MAXM = MAXN*3;
int n, m;
double p[MAXM], l[MAXN], r[MAXN], ans[MAXM];
struct seg {
int t[MAXM]; double s[MAXM]; int flg;
void cover(int x, int y, double val) {
++t[x], --t[y+1];
s[x]+=val, s[y+1]-=val;
}
void solve() {
for(int i = 1; i <= m; ++i) {
t[i] += t[i-1], s[i] += s[i-1];
if(flg) ans[i] += s[i], ans[i] -= p[i] * t[i];
else ans[i] += p[i] * t[i], ans[i] -= s[i];
s[i-1] = t[i-1] = 0;
}
s[m] = t[m] = 0;
}
}T;
int main () {
scanf("%d", &n);
for(int i = 1; i <= n; ++i) {
scanf("%lf%lf", &l[i], &r[i]);
p[++m] = l[i];
p[++m] = (l[i]+r[i])/2;
p[++m] = r[i];
}
sort(p + 1, p + m + 1);
m = unique(p + 1, p + m + 1) - p - 1;
T.flg = 0;
for(int i = 1; i <= n; ++i) {
int L = lower_bound(p + 1, p + m + 1, l[i]) - p;
int R = upper_bound(p + 1, p + m + 1, (l[i]+r[i])/2) - p - 1;
if(L <= R) T.cover(L, R, l[i]);
}
T.solve();
T.flg = 1;
for(int i = 1; i <= n; ++i) {
int L = upper_bound(p + 1, p + m + 1, (l[i]+r[i])/2) - p;
int R = upper_bound(p + 1, p + m + 1, r[i]) - p - 1;
if(L <= R) T.cover(L, R, r[i]);
}
T.solve();
LL ANS = 0;
for(int i = 1; i <= m; ++i)
ANS = max(ANS, (LL)(2*ans[i]));
cout<<ANS<<endl;
}