可能是打智(ka)算(chang)之(da)道(sai)留下的后遗症,看见Rank掉了,想把A掉的题输入优化一下再交一遍,然后就恰了一发罚时,从Rank900掉到了Rank1100…
纯模拟,没什么好说的。
#include
const int inf=0x3f3f3f3f;
using namespace std;
int main()
{
ios::sync_with_stdio(0);
cin.tie(0);
int t,n,m,x,y,tmp,ans;
cin>>t;
while(t--)
{
cin>>n>>m;
ans=inf;
for(int i=1;i<=n;i++)
{
cin>>x>>y;
tmp=m/x*y;
if(m%x)
tmp+=y;
ans=min(ans,tmp);
}
cout<<ans<<endl;
}
}
dfs,取每个分数段里最低的,最终搜索深度为4时,只要用掉的分数不超过输入的分数就行,取一个最大结果输出。
#include
const int inf=0x3f3f3f3f;
using namespace std;
int t,score;
double ans;
void dfs(double s,double g,int c)
{
if(c>4) return;
if(s>score) return;
if(c==4&&s<=score)
{
ans=max(ans,g);
return;
}
dfs(s,g,c+1);
dfs(s+60,g+1,c+1);
dfs(s+62,g+1.7,c+1);
dfs(s+65,g+2,c+1);
dfs(s+67,g+2.3,c+1);
dfs(s+70,g+2.7,c+1);
dfs(s+75,g+3,c+1);
dfs(s+80,g+3.3,c+1);
dfs(s+85,g+3.7,c+1);
dfs(s+90,g+4,c+1);
dfs(s+95,g+4.3,c+1);
}
int main()
{
cin>>t;
while(t--)
{
ans=0;
cin>>score;
dfs(0,0,0);
cout<<fixed<<setprecision(1)<<ans<<endl;
}
}
暴力美学
dp,一开始尝试从(a,b)往(1,1)跑,但是因为有多组测试数据,每组的起点不同导致跑出来的结果在各组数据间不能互通,最后试了一下反着跑,因为起点都是(1,1),所以dp出来的数据可以通用。开局直接从(1,1)跑到(1000,1000),然后打表就完事了。
一开始T了,加了输入优化卡进了时限,900ms还行。
#include
const int inf=0x3f3f3f3f;
using namespace std;
int mem[1010][1010];
int gcd(int a,int b)
{
return b ? gcd(b,a%b) : a;
}
int main()
{
ios::sync_with_stdio(0);
cin.tie(0);
for(int i=1;i<=1000;i++)
for(int j=1;j<=1000;j++)
if(gcd(i,j)==1)
mem[i][j]=max(mem[i-1][j],mem[i][j-1])+1;
else
mem[i][j]=max(mem[i-1][j],mem[i][j-1]);
int t,a,b;
cin>>t;
while(t--)
{
cin>>a>>b;
cout<<mem[a][b]<<endl;
}
}
纯模拟,枚举建城市的点,w用来存从(x,y)跑到(i,j)所用的回合数,work存(i,j)城市周围可用工作点的收益,因为城里始终要有一个人工作,所以城市点最优先,其次就是周围的点从大到小。这里加了一个前缀和(代码中变量为k的循环),每次加食物的时候就不用从1开始遍历了。
#include
using namespace std;
typedef long long ll;
const int inf=0x3f3f3f3f;
const int mod=1e9+7;
const int maxn=510;
int t,n,x,y,a[maxn][maxn],w[maxn][maxn],work[maxn][maxn][27],ans;
void solve(int round,int people,int food,int xx,int yy)
{
round++;
food+=work[xx][yy][people];
while(food>=(8*people*people))
people++;
if(people==9)
{
ans=min(ans,round);
return;
}
solve(round,people,food,xx,yy);
}
int main()
{
ios::sync_with_stdio(0);
cin.tie(0);
cin>>t;
while(t--)
{
ans=inf;
memset(a,0,sizeof(a));
memset(w,0,sizeof(w));
memset(work,0,sizeof(work));
cin>>n>>x>>y;
for(int i=1; i<=n; ++i)
for(int j=1; j<=n; ++j)
{
cin>>a[i][j];
int dis=abs(x-i)+abs(y-j);
w[i][j]=(dis>>1)+(dis&1?1:0);
}
for(int i=1; i<=n; ++i)
for(int j=1; j<=n; ++j)
{
int cnt=0;
for(int ii=-3; ii<=3; ++ii)
for(int jj=-3; jj<=3; ++jj)
if((abs(ii)+abs(jj))<=3&&i+ii>=1&&i+ii<=n&&j+jj>=1&&j+jj<=n)
{
work[i][j][++cnt]=a[i+ii][j+jj];
if(ii==0&&jj==0)
swap(work[i][j][cnt],work[i][j][1]);
}
sort(&work[i][j][2],&work[i][j][26],greater<int>());
for(int k=2; k<=9; ++k)
work[i][j][k]+=work[i][j][k-1];
solve(w[i][j],1,0,i,j);
}
cout<<ans<<endl;
}
}
每层的黑块数目单调,无论递增或递减,都是形成一个森林,森林的连通块数量为总点数-总边数。在这题中,相邻的两个圈中,如果有内外黑块边界相接,就形成了一条边,连通块数目就是总黑块数-总边数。每个圈中有一半是黑块,总黑块数=a[1]/2+a[2]/2+…+a[n]/2。对于任意一对相邻的环,设外环有x块,内环有y块,且根据题意x
#pragma GCC optimize(3)
#include
typedef long long ll;
const int maxn=11;
const int mod=1e9+7;
int t,n,a[maxn];
inline int redn()
{
int ret=0,f=1;char ch=getchar();
while (ch<'0'||ch>'9') {if (ch=='-') f=-f;ch=getchar();}
while (ch>='0'&&ch<='9') ret=ret*10+ch-'0',ch=getchar();
return ret*f;
}
ll mod_pow(ll x,ll n)
{
ll res=1;
while(n>0)
{
if(n&1)
res=res*x%mod;
x=x*x%mod;
n>>=1;
}
return res;
}
signed main()
{
t=redn();
while(t--)
{
n=redn();
for(int i=1;i<=n;++i)
a[i]=redn();
printf("%lld\n",(a[1]+a[n])%mod*mod_pow(4,mod-2)%mod);
}
}
k的大小达到了1e10,O(k)的复杂度会炸,下面是参考的O(√k)算法博客,解释非常详细。
https://www.cnblogs.com/jianjinxiani/p/13361465.html
#pragma GCC optimize(3)
#include
#define int long long
const int maxn=6;
int t,len[maxn],k;
inline int redn()
{
int ret=0,f=1;char ch=getchar();
while (ch<'0'||ch>'9') {if (ch=='-') f=-f;ch=getchar();}
while (ch>='0'&&ch<='9') ret=ret*10+ch-'0',ch=getchar();
return ret*f;
}
int cntp(int xysum,int len)
{
if(xysum>2*len||!len) return 0;
if(!xysum) return 1;
if(xysum<=len) return 4*xysum;
return (2*len-xysum+1)*4;
}
signed main()
{
t=redn();
while(t--)
{
int ans(0),w(0);
len[4]=redn();
len[3]=redn();
len[2]=redn();
len[1]=redn();
k=redn();
while(k)
{
for(int i=1;i<=4;++i)
{
if(w%i) continue;
int cnt=cntp(w/i,len[i])-cntp(w/i,len[i+1]);
ans+=std::min(cnt,k)*w;
k-=std::min(cnt,k);
}
++w;
}
printf("%lld\n",ans);
}
}
首先,如果蚊子总数少于n* m直接特判输出-1,然后对时间t二分答案,其中对每个t跑一次网络流。直接的思路是源点S连接每个窗户,边容量为各窗户的蚊子数,再从每个窗户向从此窗户出发的t时间内能到达的每个位置连接容量为inf的边,最后从每个窗户到汇点T连接容量为1的边。如果这样建图,在最坏的情况下有nmk+2个点,建图和跑网络流消耗巨大,可以观察到窗户个数k很少,我们可以通过二进制状压,压缩每个格点与所有窗户的连接情况(从第0位开始,若第i位为1,即表示t时间内蚊子可以从第i个窗户到达该点),总状态数只有2^k个,相当于把n *m个点中状态相同的点合并了,且把与汇点连边的容量合并了。
#pragma GCC optimize(3)
#include
using namespace std;
const int maxv=100;
const int inf=0x3f3f3f3f;
int cas,n,m,k,sumz,cnt[130];
struct window
{
int x,y,z;
}w[10];
struct edge
{
int to,cap,rev;
};
vector<edge> g[maxv];
int level[maxv],iter[maxv];
void add_edge(int from,int to,int cap)
{
g[from].push_back((edge){to,cap,g[to].size()});
g[to].push_back((edge){from,0,g[from].size()-1});
}
void bfs(int s)
{
memset(level,-1,sizeof(level));
queue<int> que;
level[s]=0;
que.push(s);
while(!que.empty())
{
int v=que.front();que.pop();
for(int i=0;i<g[v].size();++i)
{
edge &e=g[v][i];
if(e.cap>0&&level[e.to]<0)
{
level[e.to]=level[v]+1;
que.push(e.to);
}
}
}
}
int dfs(int v,int t,int f)
{
if(v==t) return f;
for(int &i=iter[v];i<g[v].size();++i)
{
edge &e=g[v][i];
if(e.cap>0&&level[v]<level[e.to])
{
int d=dfs(e.to,t,min(f,e.cap));
if(d>0)
{
e.cap-=d;
g[e.to][e.rev].cap+=d;
return d;
}
}
}
return 0;
}
int max_flow(int s,int t)
{
int flow=0;
while(true)
{
bfs(s);
if(level[t]<0) return flow;
memset(iter,0,sizeof(iter));
int f;
while((f=dfs(s,t,inf))>0)
flow+=f;
}
}
inline int redn()
{
int ret=0,f=1;char ch=getchar();
while (ch<'0'||ch>'9') {if (ch=='-') f=-f;ch=getchar();}
while (ch>='0'&&ch<='9') ret=ret*10+ch-'0',ch=getchar();
return ret*f;
}
int solve(int t)
{
memset(cnt,0,sizeof(cnt));
for(int i=1;i<=n;++i)
for(int j=1;j<=m;++j)
{
int state=0;
for(int num=0;num<k;++num)
if(t>=abs(i-w[num].x)+abs(j-w[num].y))
state=state|1<<num;
++cnt[state];
}
int M=pow(2,k);
for(int i=0;i<=M+k+1;++i)
g[i].clear();
for(int i=0;i<k;++i)
add_edge(M+k,M+i,w[i].z);
for(int i=0;i<M;++i)
{
add_edge(i,M+k+1,cnt[i]);
for(int j=0;j<k;++j)
if(i&1<<j)
add_edge(M+j,i,inf);
}
int flow = max_flow(M+k,M+k+1);
return flow==n*m;
}
signed main()
{
cas=redn();
while(cas--)
{
sumz=0;
n=redn();
m=redn();
k=redn();
for(int i=0;i<k;++i)
{
w[i].x=redn();
w[i].y=redn();
w[i].z=redn();
sumz+=w[i].z;
}
if(sumz<n*m)
{
printf("-1\n");
continue;
}
int lb=0,ub=n*m-2;
while(ub-lb>1)
{
int mid=(lb+ub)/2;
if(solve(mid)) ub=mid;
else lb=mid;
}
printf("%d\n",ub);
}
}
莫比乌斯反演,我不会。