再次AK了呢。(好像某谷上说宜做模拟赛我就能AK?
不过确实比昨天简单了不少。
一下又是十分简略的题解。。。
T1:3566. 阶乘
题目大意:求n的阶乘在base进制下末尾零的个数。(n和base均为10进制数
显然对于base进制,当一个数是base的倍数时末尾会有零。所以转化题意得:求m,使得 b a s e m ∗ k = n ! base^{m}*k=n! basem∗k=n!。然后将base分解质因数,然后在 n ! n! n!里面配对就好了。
考场直接上了Pollard_rho,纯粹为了好玩
话说base可以开到1e18(逃,还是不要互相残害吧
#include
#include
#include
#include
using namespace std;
const int N = 10010;
typedef long long ll;
template < class T >
inline void read(T &x)
{
char ch = getchar(); x = 0; int fg = 1;
for(;ch < '0' || ch > '9';) fg = ch == '-' ? -1 : 1, ch = getchar();
for(;ch >= '0' && ch <= '9';) x = x * 10 + (ch ^ '0'), ch = getchar(); x *= fg;
}
ll T,n,base,cur,tot,p[N],cnt[N],ans;
ll gcd(ll a,ll b) { return !b ? a : gcd(b,a % b); }
ll f_mul(ll a,ll b,ll P) { return (a * b - (ll)((long double)a / P * b) * P + P) % P; }
ll f_pow(ll a,ll x,ll P) { ll ret = 1; a = a % P; for(;x;x >>= 1) (x & 1) && (ret = f_mul(ret,a,P),1), a = f_mul(a,a,P); return ret % P; }
bool witness(ll x,ll p)
{
if(f_pow(x,p - 1,p) != 1) return 0;
for(ll k = p - 1,t;(k & 1) == 0;)
{
k >>= 1, t = f_pow(x,k,p);
if((t ^ 1) && (t ^ p - 1)) return 0;
if(t == p - 1) return 1;
}
return 1;
}
bool Miller_rabin(ll n)
{
if(n == 1) return 0;
const int c[] = { 2,3,7,61,24251,19260817 };
for(int i = 0;i < 6; ++ i)
if(n == c[i]) return 1; else if(!witness(c[i],n)) return 0;
return 1;
}
ll r,q[N];
void Pollard_rho(ll n)
{
for(;!(n & 1);) n >>= 1, q[++r] = 2;
if(n == 1) return;
if(Miller_rabin(n)) { q[++r] = n; return; }
ll x = rand() % (n - 1) + 1,y = x,c = rand() % (n - 1) + 1,g;
for(ll i = 1,j = 1; ; ++ i)
{
x = (f_mul(x,x,n) + c) % n, g = gcd(abs(x - y),n);
if(x == y) x = rand() % (n - 1) + 1,y = x,c = rand() % (n - 1) + 1,i = 0,j = 1;
if((g > 1) && (g < n)) break;
if(i == j) y = x,j <<= 1;
}
Pollard_rho(g), Pollard_rho(n / g);
}
int main()
{
for(read(T);T--;cur = 0)
{
read(n), read(base), r = tot = ans = 0, Pollard_rho(base);
sort(q + 1,q + 1 + r); for(int i = 1;i <= r; ++ i)
if(q[i] != cur) p[++tot] = q[i], cnt[tot] = 1, cur = q[i];
else ++cnt[tot];
for(int i = 1;i <= tot; ++ i)
{
ll tmp = 0;
for(ll x = n;x;x /= p[i]) tmp += x / p[i];
if(!ans) ans = tmp / cnt[i]; else ans = min(ans,tmp / cnt[i]);
}
printf("%lld\n",ans);
}
return 0;
}
T2:3567. 石油储备计划
题目大意:给出一棵树,树上的点有石油,点之间的双向边有边权,一个单位的石油通过一条边的花费是这条边的距离。求在每个点石油尽量平均的情况下的最小花费。
昨天刚学完上下界网络流。。。最近摸清了XC的出题特点,就是今天的新知识点明天或后天一定会考。
如果会上下界网络流的话这就是一道版子题了。
#include
#include
#include
#include
#include
using namespace std;
const int N = 10010,INF = 0x3f3f3f3f;
template < class T >
inline void read(T &x)
{
char ch = getchar(); x = 0; int fg = 1;
for(;ch < '0' || ch > '9';) fg = ch == '-' ? -1 : 1, ch = getchar();
for(;ch >= '0' && ch <= '9';) x = x * 10 + (ch ^ '0'), ch = getchar(); x *= fg;
}
struct Edge{ int to,nxt,flow,cost; } g[(N * 100) << 1];
int last[N],cnt = 1,a[N],cur[N];
int Q,vis[N],dis[N],n,S,T,ans,s,t,sum;
long long cos;
void add(int u,int v,int w1,int w2) { g[++cnt] = (Edge){ v,last[u],w1,w2 }, last[u] = cnt; }
void Add_Edge(int u,int v,int w1,int w2) { add(u,v,w1,w2), add(v,u,0,-w2); }
int spfa(int s,int t)
{
memset(vis,0,sizeof vis), memset(dis,0x3f,sizeof dis);
dis[t] = 0, vis[t] = 1; deque < int > q; q.push_back(t);
while(!q.empty())
{
int x = q.front(); q.pop_front();
for(int i = last[x];i;i = g[i].nxt)
if(g[i ^ 1].flow && dis[g[i].to] > dis[x] - g[i].cost)
{
dis[g[i].to] = dis[x] - g[i].cost;
if(!vis[g[i].to])
{
vis[g[i].to] = 1;
if(!q.empty() && dis[g[i].to] < dis[q.front()])
q.push_front(g[i].to); else q.push_back(g[i].to);
}
}
vis[x] = 0;
} return dis[s] < INF;
}
int dfs(int x,int flow)
{
if(x == t) { vis[t] = 1; return flow; }
int now = 0; vis[x] = 1;
for(int i = last[x];i;i = g[i].nxt)
if(!vis[g[i].to] && g[i].flow && dis[g[i].to] == dis[x] - g[i].cost)
{
int tmp = dfs(g[i].to,min(flow,g[i].flow));
g[i].flow -= tmp, g[i ^ 1].flow += tmp;
cos += 1ll * tmp * g[i].cost, now += tmp;
if(now == flow) return now;
}
return now;
}
int main()
{
for(read(Q);Q--;)
{
memset(last,0,sizeof last), cnt = 1, sum = 0, cos = 0, memset(cur,0,sizeof cur);
read(n); S = n + 1, T = S + 1, s = n + 3, t = s + 1, Add_Edge(T,S,INF,0);
for(int i = 1;i <= n; ++ i)
read(a[i]), cur[S] -= a[i], cur[i] += a[i], sum += a[i], Add_Edge(S,i,0,0);
for(int i = 1;i <= n; ++ i)
cur[T] += (sum / n), cur[i] -= (sum / n), Add_Edge(i,T,1,0);
for(int i = 1,u,v,w1;i < n; ++ i)
read(u), read(v), read(w1), Add_Edge(u,v,INF,w1), Add_Edge(v,u,INF,w1);
for(int i = 1;i <= T; ++ i) if(cur[i] > 0) Add_Edge(s,i,cur[i],0); else Add_Edge(i,t,-cur[i],0);
while(spfa(s,t))
do { memset(vis,0,sizeof vis), ans += dfs(s,INF); } while(vis[t]);
printf("%lld\n",cos);
}
return 0;
}
T3:3570. 壕壕的寒假作业
这题就是白送分给你,DAG上正着反着跑一遍就没了。
代码不贴了。。。
T4:3571. 内存分配
没有题目大意。我语文不好不知道该怎么表达。。。(懒
首先容易发现,按b从小到大的顺序一定不会有错。
假设有两个程序x和y,默认 x b < y b x_{b}
这道题的话把它离线做,然后每次询问把程序的前一个版本删掉,插入新的版本就行了。
#include
#include
#include
using namespace std;
typedef long long ll;
const ll N = 200010;
template < class T >
inline void read(T &x)
{
char ch = getchar(); x = 0; ll fg = 1;
for(;ch < '0' || ch > '9';) fg = ch == '-' ? -1 : 1, ch = getchar();
for(;ch >= '0' && ch <= '9';) x = x * 10 + (ch ^ '0'), ch = getchar(); x *= fg;
}
struct node
{
ll a,b,id;
node operator + (const node &x) const
{
node sum = (node){ 0,0,0 };
sum.b = max(b,x.b - a), sum.a = a + x.a;
return sum;
}
} p[N],t[N << 2];
ll n,m,id[N],rk[N],cur[N];
ll cmp(node a,node b) { return a.b < b.b || (a.a == b.a && a.a > b.a); }
#define ls p << 1
#define rs ls | 1
node merge(node a,node b)
{
node sum = (node){ 0,0,0 };
sum.b = max(a.b,b.b - a.a), sum.a = a.a + b.a;
return sum;
}
void change(ll p,ll x,node k,ll tl,ll tr)
{
if(tl == tr) { t[p] = (node){ k.a,k.b,k.id }; return; }
ll mid = tl + tr >> 1;
x <= mid ? change(ls,x,k,tl,mid) : change(rs,x,k,mid + 1,tr);
t[p] = t[ls] + t[rs];
}
int main()
{
read(n), read(m);
for(ll i = 1,a,b;i <= n; ++ i)
read(a), read(b), p[i] = (node){ a,b,i };
for(ll i = 1,a,b;i <= m; ++ i)
read(id[i]), read(a), read(b), p[i + n] = (node){ a,b,i + n };
sort(p + 1,p + 1 + n + m,cmp);
for(ll i = 1;i <= n + m; ++ i) rk[p[i].id] = i;
for(ll i = 1;i <= n; ++ i) change(1,rk[i],p[rk[i]],1,n + m), cur[i] = rk[i];
for(ll i = 1;i <= m; ++ i)
change(1,cur[id[i]],(node){ 0,0,0 },1,n + m), change(1,rk[i + n],p[rk[i + n]],1,n + m),
cur[id[i]] = rk[i + n], printf("%lld\n",t[1].b);
return 0;
}
今天又是奇葩的2hA3题,剩下死肝T4QWQ。我太菜了。。。