03-14考试总结
作者:互联网
Test0314
嘲讽垃圾选手的毒瘤出题人
你怎么不去吃\(**\)呢
T1
得分情况
预计分数 : 30pts
实际得分 : 80pts
考虑DP , 得到\(O(n^3)\)做法
优化 , 得到\(O(n*(k-n)^2)\)做法
得到毒瘤出题人的馈赠 , 获得额外50pts
正解
多项式优化DP , 我不会 所以不改了
T2
得分情况
预计分数 : 10pts
实际得分 : 10pts
\(O(n)\)模拟 这能写挂?
当然不可能过1e18的
正解
你考虑这个\(f\)的意义 , 可以发现 看题解 是这个 :
将 \(n\) 拆分为 : \(\sum_{i=0}^{...} a[i]*k^i\)的方案数
其中 , \(a[i]\) 取任意非负数
考虑DP , 设 :
\(f[i][j]\)为 : 用不超过\(k^j\)的任意个数凑出\(k^i\)的方案数
\(g_1[j][t]\)为 : 用不超过\(k^t\)的任意个数凑出\(j*k^{i-1}\)的方案数
于是我们有 :
\(f[i][i]=1\) , \(g_1[k][t]=f[i][t]\)
其中 , \(g_1\)为临时数组 , 对于每个\(i\)都要使用一次 , 具体转移见代码
\(h[i][j]\)为 : 用不超过\(k^j\)的任意个数凑出\(n\)的\(k^0...k^{i}\)项的方案数
\(g_2[j][t]\)为 : 用不超过\(k^t\)的任意个数已经凑出\(n\)的\(k^0...k^{i-1}\)项
现在在凑\(k^i\)项 , 当前凑到了\(j*k^i\)的方案数 , 具体转移见代码
然后用上面的这些就可以计算用不超过\(k^j\)的任意个数凑出\(n\)的方案数了 , 也就是答案
上代码
#include<bits/stdc++.h>
#define r(a) a=read<int>()
#define rl(a) a=read<ll>()
#define MAXN(a) ((max##a)+10)
using namespace std;
typedef long long ll;
const int mod=1e9+7;
const int maxk=10,maxm=120;
namespace Math{
inline void Add(int &u,int v){
u=(u%mod+v%mod)%mod;return;
}
}
using Math::Add;
int K;
__int128 n;
int f[MAXN(m)][MAXN(m)];
int g[MAXN(m)][MAXN(m)];
int h[MAXN(m)][MAXN(m)];
template<class T>inline T read();
inline int calc(){
int m=(int)(log((long double)n)/log(K)),res=0;
memset(f,0,sizeof(f));memset(g,0,sizeof(g));memset(h,0,sizeof(h));
f[0][0]=h[0][0]=1;
for(int i=1;i<=m;i=-~i){
for(int j=1;j<=K;j=-~j)
for(int t=0;t<=i;t=-~t)
g[j][t]=(j==1)?(f[i-1][t]):(0);
//清空g并赋初值
for(int j=2;j<=K;j=-~j)
for(int t=0;t< i;t=-~t)
for(int k=0;k<=t;k=-~k)
g[j][t]=(g[j][t]+1ll*g[j-1][k]*f[i-1-k][t-k]%mod)%mod;
// lim=t时 凑出 j*K^(i-1)
// 那么设前面凑出了(j-1)*K^(i-1) , lim=k
// 加入的元素lim [k,t]
// 有公因数 K^k , 提出 , lim [0,t-k] , 转移方案数变为 f[i-1-k][t-k] (都除了K^k)
for(int t=0;t<=i;t=-~t)
f[i][t]=g[K][t]+(i==t);
}
for(int i=0;i<=m;i=-~i){
int lim=n%K;n/=K;
for(int j=0;j<=lim;j=-~j)
for(int t=0;t<=i;t=-~t)
g[j][t]=(j)?(0):(h[i][t]);
//同上
for(int j=1;j<=lim;j=-~j)
for(int t=0;t<=i;t=-~t)
for(int k=0;k<=t;k=-~k)
g[j][t]=(g[j][t]+1ll*g[j-1][k]*f[i-k][t-k]%mod)%mod;
// 此处g与上相似
// lim = t 时 凑出了前i-1位 并且第i位凑到了j
// 其他同上
for(int t=0;t<=i;t=-~t){
h[i+1][t]=g[lim][t];
if(i==m)Add(res,h[m+1][t]);
}
}
return res;
}
int main(){
#ifndef ONLINE_JUDGE
freopen("j.in","r",stdin);
freopen("j.out","w",stdout);
#endif
int r(T);
while(T--){
r(K),n=read<__int128>();
printf("%d\n",calc());
}return 0;
}
template<class T>inline T read(){
T sum=0,f=1;char k=getchar();
for(;k< '0'||'9'< k;k=getchar())
if(k=='-')f=-1;
for(;'0'<=k&&k<='9';k=getchar())
sum=(sum * 10)+(k^48);
return sum*f;
}
T3
得分情况
预计分数 : 0pts
实际得分 : 0pts
样例没过你想啥呢?
实际上想到了正解
然而Sap打错 + 二分图建错
只能以"想对了"安慰一下自己了quq
正解
考虑偶数时刻在\((x,y)\) , 一步以内的都跑了 , 走一步啥都莫得
你发现你只能在走两步去打野 , 所以相邻的是吃不到的
然后考虑为啥不相邻的能吃 , 发现你可以停在原地 , 这样你就改变了在\((x,y)\)的时间的奇偶性
完事 , 对网格图染色 , 跑最大独立集
上代码
#include<bits/stdc++.h>
#define r(a) a=read<int>()
#define rl(a) a=read<ll>()
using namespace std;
typedef long long ll;
const ll inf=1ll<<62;
struct Maxflow{
struct edge{
int v,next;ll flow;
}e[100010];
int n,tail,S,T;
int head[10010];
int d[10010],gap[10010];
inline void init(){
for(int i=1;i<=n;i=-~i)
head[i]=d[i]=gap[i]=0;
n=0,tail=1;
}
inline void add(int u,int v,ll flow){
e[++tail].next=head[u],head[u]=tail;
e[tail].v=v,e[tail].flow=flow;
e[++tail].next=head[v],head[v]=tail;
e[tail].v=u,e[tail].flow=0;
}
Maxflow(){init();}
ll dfs(int u,ll flow){
if(u==T)return flow;
ll res=flow;
for(int i=head[u];i;i=e[i].next){
int v=e[i].v;
if(e[i].flow>0&&d[u]==d[v]+1){
ll det=dfs(v,min(res,e[i].flow));
e[i].flow-=det,e[i^1].flow+=det;res-=det;
if(res==0)return flow;
}
}
if((--gap[d[u]])==0)d[S]=n;
gap[++d[u]]++;
return flow-res;
}
inline ll slove(){
ll res=0;gap[0]=n;
while(d[S]<n){res+=dfs(S,inf);}
return res;
}
}G;
int n,m;
ll Val[101][101];
template<class T>inline T read();
inline int id(int x,int y){return (x-1)*m+y;}
int main(){
#ifndef ONLINE_JUDGE
freopen("zjb.in","r",stdin);
freopen("zjb.out","w",stdout);
#endif
int r(T);
while(T--){
r(n),r(m);
for(int i=1;i<=n;i=-~i)
for(int j=1;j<=m;j=-~j)
rl(Val[i][j]);
ll res=0;
for(int i=1;i<=n;i=-~i)
for(int j=1;j<=m;j=-~j)
res+=Val[i][j];
G.init();
G.S=n*m+1,G.T=G.S+1;G.n=G.T+1;
for(int i=1;i<=n;i=-~i){
for(int j=1;j<=m;j=-~j){
int d=(i+j)&1;
if(d){
G.add(G.S,id(i,j),Val[i][j]);
if(i>1)G.add(id(i,j),id(i-1,j),1e18);
if(i<n)G.add(id(i,j),id(i+1,j),1e18);
if(j>1)G.add(id(i,j),id(i,j-1),1e18);
if(j<m)G.add(id(i,j),id(i,j+1),1e18);
}
else G.add(id(i,j),G.T,Val[i][j]);
}
}
//printf("%lld\n",res);
res-=G.slove();
printf("%lld\n",res);
}
return 0;
}
template<class T>inline T read(){
T sum=0,f=1;char k=getchar();
for(;k< '0'||'9'< k;k=getchar())
if(k=='-')f=-1;
for(;'0'<=k&&k<='9';k=getchar())
sum=(sum<<1)+(sum<<3)+(k^48);
return sum*f;
}
标签:03,14,int,res,ll,凑出,read,MAXN,考试 来源: https://www.cnblogs.com/Pump-six/p/10532980.html