A.City
题意:
给一个网格,问有多少条线段两端是格点,同时中点也是格点
题解:
如果两个点的横坐标和纵坐标奇偶性都相同,那么就满足条件,所以只要求出四种情况的数量,每种情况各自算出结果相机即可
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
ll f(ll x)
{
return x*(x-1)/2;
}
int main()
{
ll n,m;
scanf("%lld%lld",&n,&m);
n++;
m++;
ll a1 = n/2,a2 = (n+1)/2,a3 = m/2,a4 = (m+1)/2;
printf("%lld\n",f(a1*a3)+f(a1*a4)+f(a2*a3)+f(a2*a4));
return 0;
}C.Dirichlet k -th root(迪利克雷卷积)
题意:
给定函数f(x)自己迪利克雷卷积k次的结果g(x),求f(x)的值,其中1<=x<=n
题解:
有一个结论: ,
那我们可以知道 ,如果有个式子满足
那么
就是我们要求的答案,对于
变形可得
,就是拓展欧几里得,此时q就是k模mod的逆元,即inv(k),所以所求为
。因此我们求出inv(k),对于这n个数求出g(x)的inv(k)次卷积就是答案。
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
const int maxn = 2e5 + 5;
const int INF = 0x3f3f3f3f;
const int mod = 998244353;
ll f[maxn], g[maxn], t[maxn];
int n, k;
ll ksm(ll a, ll b, ll mod)
{
ll ans = 1;
while (b)
{
if (b & 1)
ans = ans * a % mod;
a = a * a % mod;
b >>= 1;
}
return ans;
}
void mul(ll x[], ll y[])
{
memset(t, 0, sizeof(t));
for (int i = 1; i * i <= n; i++)
{
t[i * i] = (t[i * i] + x[i] * y[i] % mod) % mod;
for (int j = i + 1; i * j <= n; j++)
t[i * j] = (t[i * j] + x[i] * y[j] % mod + x[j] * y[i] % mod) % mod;
}
for (int i = 1; i <= n; i++)
x[i] = t[i];
}
void power(int p)
{
memset(f, 0, sizeof(f));
f[1] = 1;
while (p)
{
if (p & 1)
mul(f, g);
mul(g, g);
p >>= 1;
}
}
int main()
{
scanf("%d%d", &n, &k);
for (int i = 1; i <= n; i++)
scanf("%lld", &g[i]);
power(ksm(k, mod - 2, mod));
for (int i = 1; i <= n; i++)
printf("%lld ", f[i]);
puts("");
return 0;
}E.Flow(贪心)
题意:
给你一个n个节点和m条路径的图,若干条从源点1到汇点n长度都相等的路,而且每一条源点到汇点的路径都是独立路径互不相交,类似与链,你可让一条边容量加1另外一条边容量减去1,问使得流尽量大的最少操作数
题解:
因此路径互不相交,我们可以分别将每条路径上所有路径按容量升序排序,又因为每条路径长度都相等,我们可以将各条路径依次合并为一条新的路径。然后就可以进行贪心了,从容量最小的开始依次枚举每一点,剩余流量能加就加上。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 2e5+5;
struct Edge{
int to,w,next;
}e[maxn];
int head[maxn];
int tot,cnt,n,m;
vector<int>g[maxn];
ll addflow[maxn];
void init()
{
memset(head,-1,sizeof(head));
cnt=tot=0;
}
void addedge(int u,int v,int w)
{
e[tot].to=v;
e[tot].w=w;
e[tot].next=head[u];
head[u]=tot++;
}
void dfs(int u,int fa)
{
for(int i=head[u];~i;i=e[i].next)
{
int v = e[i].to;
if(v==fa)continue;
g[cnt].push_back(e[i].w);
dfs(v,u);
}
}
int main()
{
scanf("%d%d",&n,&m);
init();
int len;
ll flow=0;
for(int i=1;i<=m;i++)
{
int u,v,w;
scanf("%d%d%d",&u,&v,&w);
addedge(u,v,w);
flow+=w;
}
for(int i=head[1];~i;i=e[i].next)
{
int v = e[i].to;
g[++cnt].push_back(e[i].w);
dfs(v,1);
len = g[cnt].size();
sort(g[cnt].begin(),g[cnt].end());
int l=0;
while(l<len-1)
{
while(l<len-1&&g[cnt][l]==g[cnt][l+1])l++;
if(l<len)addflow[l+1]+=g[cnt][l+1]-g[cnt][l];
l++;
}
flow-=1ll*len*g[cnt][0];
}
ll ans=0;
for(int i=1;i<len;i++)
{
if(flow<len)break;
ll tmp = min(addflow[i],flow/len);
ans += 1ll * tmp * i;
flow -= 1ll * tmp * len;
}
printf("%lld\n",ans);
return 0;
}H.king(随机数)
题意:
给定T组数据,每组数据n个数,求每组数据中最长的等比数列长度,如果最长的等比数列长度小于数列长度的一半则输出-1
题解:
因为要求长度大于一半,所以如果存在等比数列相邻两个数只可能相差1或2。因此我们随机取80个数,依次求出与后2个数的公比,遍历整个数组算出长度即可
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 2e5+5;
std::mt19937 rnd(time(0));
int n;
ll a[maxn];
ll p;
ll ksm(ll a, ll n)
{
a %= p;
ll res = 1;
while (n)
{
if (n & 1)
res = res * a % p;
a = a * a % p;
n >>= 1;
}
return res;
}
int solve(int l,int r)
{
ll pre;
int res=2;
ll q=a[r]*ksm(a[l],p-2)%p;
pre = a[r];
for(int i=r+1;i<=n;i++)
if(pre*q%p==a[i])
{
pre=a[i];
res++;
}
pre=a[l];
for(int i=l-1;i>=1;i--)
if(a[i]*q%p==pre)
{
pre=a[i];
res++;
}
return res;
}
int main()
{
int T;
scanf("%d",&T);
while(T--)
{
scanf("%d%lld",&n,&p);
for(int i=1;i<=n;i++)
scanf("%lld",&a[i]);
int ans=0;
for(int i=1;i<=80;i++)
{
int x = rnd()%(n-1)+1;
for(int j=x+1;j<=n&&j<=x+2;j++)
ans=max(ans,solve(x,j));
}
if(ans<(n+1)/2)printf("-1\n");
else printf("%d\n",ans);
}
return 0;
}M.value
题意:
给定n个数,每个数都有一个值a和b,每选择一个数x那么最终结果就会加上对应的ax,但是你如果先前选择了一个数y, 那么最终结果就会减去bx,对于每个数都同理,所以最终结果只会加上一次ax,但是可以减很多次bx
题解:
可以发现只有基底相同的一些数才会相互有影响,那么我们可以对每组基底都单独算出最大贡献,最终结果就是各组贡献之和,对于每组基底我们只要暴力枚举所有的可能情况取最大值即可
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 1e5+5;
int n,a[maxn],b[maxn],vis[maxn],num[maxn],cnt,mark[maxn];
ll dfs(int pos)
{
if(pos>cnt)
{
ll res=0;
for(int i=1;i<=pos;i++)
{
if(mark[i])
{
res+=a[num[i]];
for(int j=i*2;j<=cnt;j+=i)
if(mark[j])
res-=b[num[j]];
}
}
return res;
}
mark[pos]=1;
ll res = dfs(pos+1);
mark[pos]=0;
res=max(res,dfs(pos+1));
return res;
}
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;i++)scanf("%d",&a[i]);
for(int i=1;i<=n;i++)scanf("%d",&b[i]);
ll ans=a[1];
for(int i=2;i<=n;i++)
{
if(vis[i])continue;
cnt=0;
for(ll j=i;j<=n;j*=i)
{
vis[j]=1;
num[++cnt]=j;
}
ans+=dfs(1);
}
printf("%lld\n",ans);
return 0;
} 
京公网安备 11010502036488号