2019 ICPC Asia-East Continent Final
A-City
传统签到题!
不妨枚举横竖两个维度的长度,只要都是偶数就满足条件,简单计数统计满足这种长度的线段的数量即可。
斜着的线段因为不确定往哪边斜,数量要乘 \(2\)!!!
查看代码
#include<bits/stdc++.h>
using namespace std;
long long ans;
int n,m;
int main(){
cin>>n>>m;
for(int i=0;i<=n;++i){
for(int j=0;j<=m;++j){
if(i%2||j%2||(i==0&&j==0))continue;
ans+=((i!=0&&j!=0)?2:1)*1ll*(n-i+1)*(m-j+1);
}
}
cout<<ans;
return 0;
}
E-Flow
首先可以发现最大的流量一定是总流量除以最短路取下整!
对于每条简单路径先把内部的边排序。
然后对于每一层,先看看目前能不能达到这个流量,不行就加大到下一层(因为排了序),再加就超过了的话只要补上缺的一部分即可!
查看代码
#include<bits/stdc++.h>
using namespace std;
#define int long long
int n,m,tot,s[100005],a[100005];
pair<int,int>nxt[100005];
int sum[100005];
signed main(){
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
cin>>n>>m;
int res=0;
memset(s,-1,sizeof(s));
for(int i=1;i<=m;++i){
int x,y,z;
cin>>x>>y>>z;
if(x==1){
++tot;
s[y]=z;
}
else nxt[x]=make_pair(y,z);
res+=z;
}
res/=(m/tot);
for(int i=2;i<=n;++i){
if(s[i]!=-1){
int cnt=0;
a[++cnt]=s[i];
int u=i;
while(u!=n){
a[++cnt]=nxt[u].second;
u=nxt[u].first;
}
sort(a+1,a+cnt+1);
for(int j=1;j<=cnt;++j)sum[j-1]+=a[j]-a[j-1];
}
}
int ans=0,tot=sum[0];
int x=0;
while(tot+sum[x+1]<res){
tot+=sum[++x];
ans+=x*sum[x];
}
++x;
ans+=x*(res-tot);
cout<<ans;
return 0;
}
H-King
随机化算法好!
因为长度要超过 \(\frac{n}{2}\),所以一定会有挨着或者中间隔了一个的情况!
所以我只要 shuffle()
一个顺序数组,取前 \(100\) 个 check()
一下就可以了!
可以发现,取前 \(100\) 个几乎不可能挂!
然后写个逆元啥的,问题就解决了!
查看代码
#include<bits/stdc++.h>
using namespace std;
#define int long long
int t,n,p,r[200005],a[200005];
int qpow(int a,int b){
int ans=1,base=a;
while(b){
if(b&1)ans=ans*base%p;
base=base*base%p;
b>>=1;
}
return ans;
}
int inv(int x){
return qpow(x,p-2);
}
mt19937 rnd(time(0));
signed main(){
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
cin>>t;
while(t--){
cin>>n>>p;
for(int i=1;i<=n;++i)cin>>a[i];
for(int i=1;i<n;++i)r[i]=i+1;
shuffle(r+1,r+n,rnd);
int maxn=0;
for(int i=1;i<=100;++i){
int x=r[i];
int q=a[x]*inv(a[x-1])%p;
int invq=inv(q),s=a[x-1],sum=0;
for(int j=x-1;j>=1;j--){
if(s==a[j])++sum,s=s*invq%p;
}
s=a[x];
for(int j=x;j<=n;++j)if(s==a[j])++sum,s=s*q%p;
maxn=max(maxn,sum);
}
for(int i=1;i<n-1;++i)r[i]=i+2;
shuffle(r+1,r+n-1,rnd);
for(int i=1;i<=100;++i){
int x=r[i];
int q=a[x]*inv(a[x-2])%p;
int invq=inv(q),s=a[x-2],sum=0;
for(int j=x-2;j>=1;j--){
if(s==a[j])++sum,s=s*invq%p;
}
s=a[x];
for(int j=x;j<=n;++j)if(s==a[j])++sum,s=s*q%p;
maxn=max(maxn,sum);
}
if(maxn<n/2.0)cout<<-1<<'\n';
else cout<<maxn<<'\n';
}
}
M-Value
非常抽象啊!以至于我一开始打算网络流
就是,你发现,对于一个数 \(k\),如果它对谁开根都不是整数,那么选不选这个数的影响范围只有 \(k^2,k^3...\),元素数量是 \(\log_kn\) 级别的。
然后你发现,满足条件的 \(k\) 只能是 \(1\) 到 \(\sqrt{n}\)!
那么我只有 \(2^{\log_kn}\) 搜索!
复杂度 \(\Theta(\sqrt{n}\times 2^{\log_kn}) \le \Theta(n\sqrt{n})\)
稳过!!!
查看代码
#include<bits/stdc++.h>
using namespace std;
int n,a[100005],tot,b[100005];
vector<int>v[355];
bool vis[100005],flg[25];
long long ans;
void check(int x){
long long res=0;
for(int i=0;i<v[x].size();++i)if(flg[i+1])res+=a[v[x][i]];
for(int i=0;i<v[x].size();++i){
for(int j=0;j<i;++j){
if((i+1)%(j+1))continue;
if(flg[i+1]&&flg[j+1])res-=b[v[x][i]];
}
}
ans=max(ans,res);
return;
}
void dfs(int x,int cur){
if(cur==v[x].size()+1){
check(x);
return;
}
flg[cur]=0;
dfs(x,cur+1);
flg[cur]=1;
dfs(x,cur+1);
flg[cur]=0;
}
int main(){
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
cin>>n;
for(int i=1;i<=n;++i)cin>>a[i];
for(int i=1;i<=n;++i)cin>>b[i];
for(int i=2;i<=sqrt(n);++i){
if(vis[i])continue;
vis[i]=1;
tot++;
for(int j=i;j<=n;j*=i)vis[j]=1,v[tot].push_back(j);
}
long long sum=0;
for(int i=1;i<=tot;++i){
ans=-1e9;
memset(flg,0,sizeof(flg));
dfs(i,1);
sum+=ans;
}
for(int i=1;i<=n;++i)if(!vis[i])sum+=a[i];
cout<<sum;
return 0;
}