2023.11.4
提前打摆开始写总结。
A
记 \(\displaystyle f(x)=\min_{i\in \mathbb{N^+}}\),求 \(\displaystyle \sum_{i=1}^{n}f(i)\).
答案模 \(1\mathrm{e}9+7\),多测。
\(n\le 10^{16}\),\(T\le 10^4\).
从小到大考虑每个 \(f(i)\) 的出现次数。
若当前求 \(x\) 的出现次数,那么符合的是 \(\bmod x\not=0\) 且 \(\bmod y=0,y\in[2,x)\) 的数。
右边即 \(\bmod \operatorname{lcm}(2,\dots,x-1)=0\).
求 \(\bmod x\not=0\) 且 \(\bmod t=0\) 的数的个数,容易得到为 \(\displaystyle \lfloor\frac{n}{t}\rfloor-\lfloor\frac{n}{\operatorname{lcm}(t,x)}\rfloor\).
点击查看代码
#include<bits/stdc++.h>
#define ll long long
#define P 1000000007
using namespace std;
ll read(){
ll x=0,w=1;char ch=getchar();
while(!isdigit(ch)){if(ch=='-')w=-1;ch=getchar();}
while(isdigit(ch))x=(x<<3)+(x<<1)+(ch^48),ch=getchar();
return x*w;
}
ll n;
void solve(){
n=read();
ll ans=0;
for(ll i=2,s=1,lcm;s<=n;s=lcm,i++){
lcm=s/__gcd(s,i)*i;
ans=(ans+(n/s-n/lcm)%P*i)%P;
}
printf("%lld\n",ans);
}
int main(){
int T=read();
while(T--)solve();
return 0;
}
B
*2000.
\(n\times m\) 的矩阵,进行 \(k\) 次操作,每次选出一行或一列,将其和计入贡献,并将每个格子上的值减去 \(p\).
试最大化贡献。
\(n,m,a_{i,j}\le 10^3\),\(k\le 10^6\),\(1\le p\le 100\).
显然操作顺序不影响答案最优性。考虑选了 \(i\) 行,\(k-i\) 列,最终需要减去 \(i\cdot (k-i)\cdot p\) 的贡献。
用两个优先队列记录选出若干行或列的最大贡献即可。
点击查看代码
#include<bits/stdc++.h>
#define ll long long
#define N 1010
#define M 1000010
using namespace std;
int read(){
int x=0,w=1;char ch=getchar();
while(!isdigit(ch)){if(ch=='-')w=-1;ch=getchar();}
while(isdigit(ch))x=(x<<3)+(x<<1)+(ch^48),ch=getchar();
return x*w;
}
int n,m,k;ll p;
ll line[N],row[N];
priority_queue<ll>A,B;
ll f[M],g[M],ans=-1e18;
int main(){
n=read(),m=read(),k=read(),p=read();
for(int i=1,x;i<=n;i++)
for(int j=1;j<=m;j++)
x=read(),line[i]+=x,row[j]+=x;
for(int i=1;i<=n;i++)A.push(line[i]);
for(int j=1;j<=m;j++)B.push(row[j]);
for(int i=1;i<=k;i++){
ll cur=A.top();A.pop();
f[i]=f[i-1]+cur,A.push(cur-p*m);
}
for(int i=1;i<=k;i++){
ll cur=B.top();B.pop();
g[i]=g[i-1]+cur,B.push(cur-p*n);
}
for(int i=0;i<=k;i++){
ll cur=f[i]+g[k-i]-1ll*i*(k-i)*p;
ans=max(ans,cur);
}
printf("%lld\n",ans);
return 0;
}
C
*2400.
将 \(n\) 个括号串任意拼接,最大化前缀合法括号串个数。
\(n\le 20\),\(\sum |s|\le 4\times 10^5\).
很好想。垃圾主席树 WA on Test 43,不想玩了。
莫名其妙调出来了。很难绷得住。
时间复杂度 \(O(n\cdot 2^n\cdot \log n)\).
点击查看代码
#pragma GCC optimize(3,"Ofast","inline")
#include<bits/stdc++.h>
#define N 20
#define S 400010
#define M (1<<20)
#define pii pair<int,int>
#define fi first
#define se second
#define mp make_pair
using namespace std;
int read(){
int x=0,w=1;char ch=getchar();
while(!isdigit(ch)){if(ch=='-')w=-1;ch=getchar();}
while(isdigit(ch))x=(x<<3)+(x<<1)+(ch^48),ch=getchar();
return x*w;
}
int n;char ch[S];
#define ls(x) tr[x].ls
#define rs(x) tr[x].rs
#define cnt(x) tr[x].cnt
struct node{
int ls,rs,cnt;
};
struct str{
int len,dlt;//dlt -> len
int a[S],b[S];
int rt[S],tot;
vector<node>tr;
void insert(int &p,int pre,int l,int r,int x){
tr[p=++tot]=tr[pre];
if(l==r)return cnt(p)++,void();
int mid=(l+r)>>1;
if(x<=mid)insert(ls(p),ls(pre),l,mid,x);
else insert(rs(p),rs(pre),mid+1,r,x);
}
int query(int p,int l,int r,int x){
if(!p)return 0;
if(l==r)return cnt(p);
int mid=(l+r)>>1;
return x<=mid?query(ls(p),l,mid,x):query(rs(p),mid+1,r,x);
}
void init(char *s,int _len){
len=dlt=_len;
tr.resize(len<<6);
for(int i=0;i<len;i++)
a[i]=b[i]=(i?a[i-1]:0)+(s[i]=='('?1:-1);
for(int i=1;i<len;i++)
b[i]=min(b[i],b[i-1]);
for(int i=0;i<len;i++){
insert(rt[i],i?rt[i-1]:0,0,len+dlt,a[i]+dlt);
b[i]=-b[i];
}
}
int find(int x){
return upper_bound(b,b+len,x)-b-1;
}
int qry(int L,int x){
if(L==-1||x+dlt<0)return 0;
return query(rt[L],0,len+dlt,x+dlt);
}
}s[N];
int f[M],sval[M];
int ans;
int main(){
n=read();
for(int i=0;i<n;i++)
scanf("%s",ch),s[i].init(ch,strlen(ch));
int lim=(1<<n);
memset(f,-0x3f,sizeof(f)),f[0]=0;
for(int i=1;i<lim;i++){
for(int j=0;j<n;j++){
if(!((i>>j)&1))continue;
sval[i]=sval[i^(1<<j)]+s[j].a[s[j].len-1];
break;
}
for(int j=0,pos;j<n;j++){
if(!((i>>j)&1))continue;
pos=s[j].find(sval[i^(1<<j)]);
int tp=f[i^(1<<j)]+s[j].qry(pos,-sval[i^(1<<j)]);
ans=max(ans,tp);
if(pos==s[j].len-1)f[i]=max(f[i],tp);
}
ans=max(ans,f[i]);
}
printf("%d\n",ans);
return 0;
}
D
构造一个 DAG,使 \(1\) 到 \(114\) 的路径条数为 \(n+1\),\([0,n]\) 在这些路径的边权和中均出现过一次。
- 点编号 \(\in[1,114]\),边权 \(\in \mathbb{N}\).
\(n\le 32500\),保证存在点数 \(\le 18\),边数 \(\le 45\),边权 \(\le n\) 的方案。(点数包含 \(1\) 和 \(114\).)