8月3日做题日记
8月3日刷题日记
P5689 [CSP-S2019 江西] 多叉堆
准确来说应该是昨天最后一道,但是某种原因没有做(((
数数题。
本质上是问一棵完全二叉树有多少种拓扑序。
乘法原理。\(f[i]=f_[i] \times f[son] \times C_{Size_i-1}^{Size_{son}}\)
除去 \(i\) 节点还剩 \(Size[i]-1\) 个节点,在里面选 \(Size[son]\) 个填入子树中,乘起来就行。
#include<bits/stdc++.h>
#define INF 0x3f3f3f3f
#define debug cout<<"Szt ak ioi\n";
#define int long long
const int Mod=1e9+7;
const int N=1e6+7,M=2e3+1;
using namespace std;
inline int read() {
int x=0,f=0;
char ch=getchar();
while(!isdigit(ch))f|=(ch=='-'),ch=getchar();
while(isdigit(ch))x=(x<<1)+(x<<3)+(ch&15),ch=getchar();
return f?-x:x;
}
int n,q,ls;
int Size[N],fac[N],fa[N],Ans[N];
int find(int x){return fa[x]==x?x:fa[x]=find(fa[x]);}
int Pow(int a,int b){
int res=1;a%=Mod;
while(b){
if(b&1) res=(res*a)%Mod;
b>>=1;a=(a*a)%Mod;
}return res;
}
void Init(){
// inv[1]=1;
fac[0]=1;
for(int i=1;i<=n;i++)fa[i]=i,Size[i]=Ans[i]=1;
for(int i=1;i<=n;i++)fac[i]=(fac[i-1]*i)%Mod;
}
int C(int n,int m){return fac[n]%Mod*Pow(fac[m],Mod-2)%Mod*Pow(fac[n-m],Mod-2)%Mod;}
signed main() {
n=read(),q=read();Init();
for(int i=1;i<=q;i++){
int opt=read();
if(opt&1){
int x=(read()+ls)%n+1,y=(read()+ls)%n+1;
int uf=find(x),vf=find(y);
Ans[vf]=(Ans[uf]%Mod*Ans[vf]%Mod*C(Size[vf]-1+Size[uf],Size[uf])%Mod)%Mod;
fa[uf]=vf;Size[vf]+=Size[uf];
}else{
int x=(read()+ls)%n+1;x=find(x);
printf("%lld\n",Ans[x]);ls=Ans[x];
}
}
return 0;
}
P1350 车的放置
数数题。
噶开分成两块。
上面 \(a \times b\) 和下面 \(d \times (a+c)\),不在同一行和同一列就是选 \(k\) 行和 \(k\) 列。
在 \(n \times n\) 的矩形中选取 \(k \times k\) 个点满足上面的条件就是 \(C_n^k \times C_n^k\),然后在选出来的点组成的矩形中共有 \(k!\) 种选法,乘法原理,第一行有 \(k\) 种选法,第二行有 \(k-1\) 种……
下面那个矩形同理。
答案就是:\(\displaystyle \sum_{i=0}^{k} i! \times C_{a}^{i} \times C_{c}^{i} \times (k-i)! \times C_{a+c-i}^{k-i} \times C_{d}^{k-i}\)。
模数不是很大,用 Lucas 解决。
#include<bits/stdc++.h>
#define INF 0x3f3f3f3f
#define debug cout<<"Szt ak ioi\n";
#define int long long
const int Mod=1e5+3;
const int N=1e6+7,M=2e3+1;
using namespace std;
inline int read() {
int x=0,f=0;
char ch=getchar();
while(!isdigit(ch))f|=(ch=='-'),ch=getchar();
while(isdigit(ch))x=(x<<1)+(x<<3)+(ch&15),ch=getchar();
return f?-x:x;
}
void print(int x){
if(x>9) print(x/10);
putchar(x%10+'0');
}
int Pow(int a,int b){
int res=1;while(b){if(b&1) res=(res*a)%Mod;
b>>=1;a=(a*a)%Mod;}return res;
}
int a,b,c,d,k,fac[N],inv[N];
void init(){
fac[0]=1;
for(int i=1;i<=N-2;i++) fac[i]=(fac[i-1]*i)%Mod;
for(int i=0;i<Mod;i++) inv[i]=Pow(i,Mod-2);
}
int C(int n,int m){ return fac[n]%Mod*inv[fac[m]]%Mod*inv[fac[n-m]]%Mod;}
int Lucas(int n,int m){
if(!m) return 1;
return Lucas(n/Mod,m/Mod)*C(n%Mod,m%Mod)%Mod;
}
signed main() {
a=read(),b=read(),c=read(),d=read(),k=read();
init();int Ans=0;
for(int i=0;i<=k;i++){
if(i>a||i>b||k-i>a+c-i||k-i>d) continue;
int res=1;
res*=fac[i];if(res) res%=Mod;
res*=Lucas(a,i);if(res) res%=Mod;
res*=Lucas(b,i);if(res) res%=Mod;
res*=fac[k-i];if(res) res%=Mod;
res*=Lucas(a+c-i,k-i);if(res) res%=Mod;
res*=Lucas(d,k-i);if(res) res%=Mod;
if(res==0) continue;Ans+=res;if(Ans) Ans%=Mod;
}
print(Ans%Mod);
return 0;
}
P6057 [加油武汉]七步洗手法
数数题,随便搞一下就行了。
#include<bits/stdc++.h>
#define INF 0x3f3f3f3f
#define debug cout<<"Szt ak ioi\n";
#define int long long
const int Mod=1e9+7;
const int N=1e6+7,M=2e3+1;
using namespace std;
inline int read() {
int x=0,f=0;
char ch=getchar();
while(!isdigit(ch))f|=(ch=='-'),ch=getchar();
while(isdigit(ch))x=(x<<1)+(x<<3)+(ch&15),ch=getchar();
return f?-x:x;
}
int d[N],n,m;
signed main() {
n=read(),m=read();
for(int i=1;i<=m;i++){
int u=read(),v=read();
d[u]++;d[v]++;
}int ans=0;
for(int i=1;i<=n;i++) ans+=(d[i]*(n-1-d[i]));
cout<<n*(n-1)*(n-2)/6-ans/2;
return 0;
}
P3223 [HNOI2012] 排队
正难则反,老师不相邻 = 全部 - 老师相邻。
然后再贺上一个傻逼高精就过了。
#include<bits/stdc++.h>
#define INF 0x3f3f3f3f
#define debug cout<<"Szt ak ioi\n";
#define LL long long
const int Mod = 1e9 + 7;
const int N = 1e6 + 7, M = 2e3 + 1;
using namespace std;
inline int read() {
int x = 0, f = 0;
char ch = getchar();
while (!isdigit(ch))f |= (ch == '-'), ch = getchar();
while (isdigit(ch))x = (x << 1) + (x << 3) + (ch & 15), ch = getchar();
return f ? -x : x;
}
const int Big_B = 10;
const int Big_L = 1;
inline int intcmp_ (int a, int b) {
if (a > b) return 1;
return a < b ? -1 : 0;
}
struct Int {
#define rg register
inline int max (int a, int b) {
return a > b ? a : b;
}
inline int min (int a, int b) {
return a < b ? a : b;
}
std :: vector <int> c;
Int () {}
Int (int x) {
for (; x > 0; c.push_back (x % Big_B), x /= Big_B);
}
Int (LL x) {
for (; x > 0; c.push_back (x % Big_B), x /= Big_B);
}
inline void CrZ () {
for (; !c.empty () && c.back () == 0; c.pop_back ());
}
inline Int &operator += (const Int &rhs) {
c.resize (max (c.size (), rhs.c.size ()));
rg int i, t = 0, S;
for (i = 0, S = rhs.c.size (); i < S; ++ i)
c[i] += rhs.c[i] + t, t = c[i] >= Big_B, c[i] -= Big_B & (-t);
for (i = rhs.c.size (), S = c.size (); t && i < S; ++ i)
c[i] += t, t = c[i] >= Big_B, c[i] -= Big_B & (-t);
if (t) c.push_back (t);
return *this;
}
inline Int &operator -= (const Int &rhs) {
c.resize (max (c.size (), rhs.c.size ()));
rg int i, t = 0, S;
for (i = 0, S = rhs.c.size (); i < S; ++ i)
c[i] -= rhs.c[i] + t, t = c[i] < 0, c[i] += Big_B & (-t);
for (i = rhs.c.size (), S = c.size (); t && i < S; ++ i)
c[i] -= t, t = c[i] < 0, c[i] += Big_B & (-t);
CrZ ();
return *this;
}
inline Int &operator *= (const Int &rhs) {
rg int na = c.size (), i, j, S, ai;
c.resize (na + rhs.c.size ());
LL t;
for (i = na - 1; i >= 0; -- i) {
ai = c[i], t = 0, c[i] = 0;
for (j = 0, S = rhs.c.size (); j < S; ++ j) {
t += c[i + j] + (LL) ai * rhs.c[j];
c[i + j] = t % Big_B, t /= Big_B;
}
for (j = rhs.c.size (), S = c.size (); t != 0 && i + j < S; ++ j)
t += c[i + j], c[i + j] = t % Big_B, t /= Big_B;
assert (t == 0);
}
CrZ ();
return *this;
}
inline Int &operator /= (const Int &rhs) {
return *this = div (rhs);
}
inline Int &operator %= (const Int &rhs) {
return div (rhs), *this;
}
inline Int &shlb (int l = 1) {
if (c.empty ()) return *this;
c.resize (c.size () + l);
rg int i;
for (i = c.size () - 1; i >= l; -- i) c[i] = c[i - l];
for (i = 0; i < l; ++ i) c[i] = 0;
return *this;
}
inline Int &shrb (int l = 1) {
for (rg int i = 0; i < c.size () - l; ++ i) c[i] = c[i + l];
c.resize (max (c.size () - l, 0));
return *this;
}
inline Int div (const Int &rhs) {
assert (!rhs.c.empty ());
Int q, r;
rg int i;
if (rhs > *this) return 0;
q.c.resize (c.size () - rhs.c.size () + 1);
rg int _l, _r, mid;
for (i = c.size () - 1; i > c.size () - rhs.c.size (); -- i) r.shlb (), r += c[i];
for (i = c.size () - rhs.c.size (); i >= 0; -- i) {
r.shlb ();
r += c[i];
if (r.Comp (rhs) < 0) q.c[i] = 0;
else {
_l = 0, _r = Big_B;
for (; _l != _r; ) {
mid = _l + _r >> 1;
if ((rhs * mid).Comp (r) <= 0) _l = mid + 1;
else _r = mid;
}
q.c[i] = _l - 1, r -= rhs * q.c[i];
}
}
q.CrZ (), *this = r;
return q;
}
inline int Comp (const Int &rhs) const {
if (c.size () != rhs.c.size ()) return intcmp_ (c.size (), rhs.c.size ());
for (rg int i = c.size () - 1; i >= 0; -- i)
if (c[i] != rhs.c[i]) return intcmp_ (c[i], rhs.c[i]);
return 0;
}
friend inline Int operator + (const Int &lhs, const Int &rhs) {
Int res = lhs;
return res += rhs;
}
inline friend Int operator - (const Int &lhs, const Int &rhs) {
if (lhs < rhs) {
putchar ('-');
Int res = rhs;
return res -= lhs;
} else {
Int res = lhs;
return res -= rhs;
}
}
friend inline Int operator * (const Int &lhs, const Int &rhs) {
Int res = lhs;
return res *= rhs;
}
friend inline Int operator / (const Int &lhs, const Int &rhs) {
Int res = lhs;
return res.div (rhs);
}
friend inline Int operator % (const Int &lhs, const Int &rhs) {
Int res = lhs;
return res.div (rhs), res;
}
friend inline std :: ostream &operator << (std :: ostream &out, const Int &rhs) {
if (rhs.c.size () == 0) out << "0";
else {
out << rhs.c.back ();
for (rg int i = rhs.c.size () - 2; i >= 0; -- i)
out << std :: setfill ('0') << std :: setw (Big_L) << rhs.c[i];
}
return out;
}
friend inline std :: istream &operator >> (std :: istream &in, Int &rhs) {
static char s[100000];
in >> s + 1;
int Len = strlen (s + 1);
int v = 0;
LL r = 0, p = 1;
for (rg int i = Len; i >= 1; -- i) {
++ v;
r = r + (s[i] - '0') * p, p *= 10;
if (v == Big_L) rhs.c.push_back (r), r = 0, v = 0, p = 1;
}
if (v != 0) rhs.c.push_back (r);
return in;
}
friend inline bool operator < (const Int &lhs, const Int &rhs) {
return lhs.Comp (rhs) < 0;
}
friend inline bool operator <= (const Int &lhs, const Int &rhs) {
return lhs.Comp (rhs) <= 0;
}
friend inline bool operator > (const Int &lhs, const Int &rhs) {
return lhs.Comp (rhs) > 0;
}
friend inline bool operator >= (const Int &lhs, const Int &rhs) {
return lhs.Comp (rhs) >= 0;
}
friend inline bool operator == (const Int &lhs, const Int &rhs) {
return lhs.Comp (rhs) == 0;
}
friend inline bool operator != (const Int &lhs, const Int &rhs) {
return lhs.Comp (rhs) != 0;
}
#undef rg
};
int n, m;
Int fac[N];
Int Pow(Int a, int b) {
Int res = 1;
while (b) {
if (b & 1) res *= a;
b >>= 1;
a *= a;
}
return res;
}
Int A(int n, int m) {
if(m>n) return 0;
return fac[n] / fac[n - m];
}
Int C(int n, int m) {
if(m>n) return 0;
return fac[n] / (fac[n - m] * fac[m]);
}
signed main() {
n = read(), m = read();
fac[0] = 1;
for (int i = 1; i <= n + 5; i++) fac[i] = fac[i - 1] * i;
Int Ans;
Ans = (A(n + 2, n + 2) * A(m, m) * C(n + 3, m));
Ans -= (A(2, 2) * A(n + 1, n + 1) * A(m, m) * C(n + 2, m));
return cout << Ans, 0;
}
P1763 埃及分数
迭代加深搜索。
剪枝条件:剩下分数是 \(\frac{x}{y}\) ,剩下层数是 \(dep\) ,如果这些数就算平分了也比前面的 \(Ans\) 大,就不用搜下去了。还有就是,搜索范围不能超过剩下的平均数。搞一搞就行了。
#include<bits/stdc++.h>
#define INF 0x3f3f3f3f
#define debug cout<<"Szt ak ioi\n";
#define int long long
const int Mod=1e9+7;
const int N=1e6+7,M=2e3+1;
using namespace std;
inline int read() {
int x=0,f=0;
char ch=getchar();
while(!isdigit(ch))f|=(ch=='-'),ch=getchar();
while(isdigit(ch))x=(x<<1)+(x<<3)+(ch&15),ch=getchar();
return f?-x:x;
}
bool flg;
int Ans[N],T[N],Max,Lim,Zi,Mu;
void dfs(int dep,int a,int b,int pre){
if(dep==Lim+1){
if(!a){
flg=1;
if(Ans[Lim]<T[Lim]){
for(int i=1;i<=Lim;i++) T[i]=Ans[i];
Max=Ans[Lim];
}
}
return;
}
if(b*(Lim+1-dep)/a>Max||Ans[dep]>Max) return;
for(int i=max(pre,b/a);i<=b*(Lim+1-dep)/a;i++)
Ans[dep]=i,dfs(dep+1,a*i-b,b*i,i+1);
}
signed main() {
Zi=read(),Mu=read();
for(Lim=1;;Lim++){
T[Lim]=INF;
Max=INF;
dfs(1,Zi,Mu,1);
if(flg) break;
}
for(int i=1;i<=Lim;i++) cout<<T[i]<<" ";
return 0;
}
P4799 [CEOI2015 Day2] 世界冰球锦标赛
折半搜索板子,寄吧不是没开 128 就是数组开小就是 TLE,真拉啊。
就是把数组锯开,前后各算一部分,合起来,复杂度 \(O(2^{\frac{n}{2}})\)。
#include<bits/stdc++.h>
#define INF 0x3f3f3f3f
#define debug cout<<"Szt ak ioi\n";
#define LL __int128
#define int __int128
const int Mod=1e9+7;
const int N=1e6+7,M=2e3+1;
using namespace std;
inline int read() {
int x=0,f=0;
char ch=getchar();
while(!isdigit(ch))f|=(ch=='-'),ch=getchar();
while(isdigit(ch))x=(x<<1)+(x<<3)+(ch&15),ch=getchar();
return f?-x:x;
}
LL n,m,mid,a[N],Ans;
vector<int>s1,s2;
void dfs1(int pos,int cost){
if(cost>m) return;
if(pos>mid) return s1.push_back(cost),void();
dfs1(pos+1,cost+a[pos]);
dfs1(pos+1,cost);
}
void dfs2(int pos,int cost){
if(cost>m) return;
if(pos>n) return s2.push_back(cost),void();
dfs2(pos+1,cost+a[pos]);
dfs2(pos+1,cost);
}
void print(LL x){
if(x>9) print(x/10);
putchar(x%10+'0');
}
signed main() {
n=read(),m=read();mid=(n+1)/2;
for(int i=1;i<=n;i++)a[i]=read();
sort(a+1,a+n+1);
dfs1(1,0);dfs2(mid+1,0);
sort(s2.begin(),s2.end());
for(auto &Jb:s1) Ans+=upper_bound(s2.begin(),s2.end(),m-Jb)-s2.begin();
print(Ans);
return 0;
}
SP29461 AROPE3 - Alphabetic Rope3
随手切平衡树,看出来这俩傻逼操作其实就是翻转,一操作就是转 \(1\) 到 \(l-1\),然后转 \(1\) 到 \(r\);二操作就是转 \(r+1\) 到 \(n\) 再 \(l\) 到 \(n\)。文艺平衡树搞一下就行了。
#include<bits/stdc++.h>
#define INF 0x3f3f3f3f
#define lson(pos) tree[pos].l
#define rson(pos) tree[pos].r
#define debug cout<<"Szt ak ioi\n";
//#define int long long
const int Mod=1e9+7;
const int N=1e6+7,M=2e3+1;
using namespace std;
inline int read() {
int x=0,f=0;
char ch=getchar();
while(!isdigit(ch))f|=(ch=='-'),ch=getchar();
while(isdigit(ch))x=(x<<1)+(x<<3)+(ch&15),ch=getchar();
return f?-x:x;
}
namespace FHQ{
int root,idx;
struct node{int l,r,Size,val,lazy,Rand;}tree[N];
int new_node(int val){tree[++idx]=(node){0,0,1,val,0,rand()};return idx;}
void push_up(int pos){tree[pos].Size=tree[lson(pos)].Size+tree[rson(pos)].Size+1;}
void push_down(int pos){
if(!tree[pos].lazy) return;swap(lson(pos),rson(pos));
tree[lson(pos)].lazy^=1,tree[rson(pos)].lazy^=1;tree[pos].lazy=0;
}
void split(int pos,int Size,int &x,int &y){
if(!pos) return x=y=0,void();push_down(pos);
if(tree[lson(pos)].Size+1<=Size) x=pos,split(tree[pos].r,Size-tree[lson(pos)].Size-1,tree[pos].r,y);
else y=pos,split(tree[pos].l,Size,x,tree[pos].l);push_up(pos);
}
int merge(int x,int y){
if(!x||!y) return x|y;
if(tree[x].Rand<=tree[y].Rand){push_down(x),rson(x)=merge(rson(x),y);push_up(x);return x;}
else {push_down(y);lson(y)=merge(x,lson(y));push_up(y);return y;}
}
void reverse(int l,int r){
int x,y,z;if(l>r)return;
split(root,l-1,x,y);split(y,r-l+1,y,z);
tree[y].lazy^=1;root=merge(merge(x,y),z);
}
void Print(int pos){
if(!pos)return;push_down(pos);
Print(tree[pos].l);putchar(tree[pos].val);Print(tree[pos].r);
}
}
int n;
char ch[N];
signed main() {
srand(time(0));
cin>>ch+1;int len=strlen(ch+1);
n=read();
for(int i=1;i<=len;i++) FHQ::root=FHQ::merge(FHQ::root,FHQ::new_node(ch[i]));
for(int i=1;i<=n;i++){
int opt=read();
if(opt==1){
int l=read()+1,r=read()+1;
FHQ::reverse(1,l-1),FHQ::reverse(1,r);
} else if(opt==2){
int l=read()+1,r=read()+1;
FHQ::reverse(r+1,len),FHQ::reverse(l,len);
}else{
int pos=read()+1,x,y,z;
FHQ::split(FHQ::root,pos-1,x,y);
FHQ::split(y,1,y,z);
putchar(FHQ::tree[y].val);puts("");
FHQ::root=FHQ::merge(FHQ::merge(x,y),z);
}
// FHQ::Print(FHQ::root);puts("");
}
return 0;
}
SP4491 PGCD - Primes in GCD Table
平凡莫反题,随手化一下就行了。
#include<bits/stdc++.h>
#define INF 0x3f3f3f3f
//#define int long long
const int N=1e7+7;
const int M=1e7+10;
using namespace std;
inline int read() {
int x=0,f=0;
char ch=getchar();
while(!isdigit(ch))f|=(ch=='-'),ch=getchar();
while(isdigit(ch))x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
return f?-x:x;
}
int mu[M],prime[M],sum[M],f[M],sc;
bool vis[M];
void Mu(){
vis[1]=mu[1]=1;
for(int i=2;i<=N;i++){
if(!vis[i]) prime[++sc]=i,mu[i]=-1;
for(int j=1;j<=sc&&i*prime[j]<=N;j++){
vis[i*prime[j]]=1;
if(!(i%prime[j])){
mu[i*prime[j]]=0;
break;
}
mu[i*prime[j]]=-mu[i];
}
}
for(int i=1;i<=sc;i++)
for(int j=1;prime[i]*j<=N;j++)
f[prime[i]*j]+=mu[j];
for(int i=1;i<=N;i++) sum[i]=sum[i-1]+f[i];
}
void Main(){
int n=read(),m=read();
if(n>m) swap(n,m);
int l=1,r;
long long Ans=0;
while(l<=n){
r=min(n/(n/l),m/(m/l));
Ans+=1LL*(n/l)*(m/l)*(sum[r]-sum[l-1]);
l=r+1;
}
printf("%lld\n",Ans);
}
signed main() {
Mu();int T=read();
while(T--)Main();
return 0;
}
今天好像还可以,但是??再接再厉吧。