签到题
int n,m,ans;
int main() {
int _;qr(_); while(_--) {
qr(n); qr(m); ans=1e9;
for(int i=1;i<=n;i++) {
int x,y; qr(x); qr(y);
ans=min(ans,((m-1)/x+1)*y);
}
pr2(ans);
}
return 0;
}
比赛的时候没有多想直接打表.
double f[N],g[N];
int main() {
for(int i=95;i<=100;i++) g[i]=4.3;
for(int i=90;i<=94;i++) g[i]=4;
for(int i=85;i<=89;i++) g[i]=3.7;
for(int i=80;i<=84;i++) g[i]=3.3;
for(int i=75;i<=79;i++) g[i]=3;
for(int i=70;i<=74;i++) g[i]=2.7;
for(int i=67;i<=69;i++) g[i]=2.3;
g[65]=g[66]=2;
for(int i=62;i<=64;i++) g[i]=1.7;
for(int i=60;i<=61;i++) g[i]=1;
for(int i=0;i<=100;i++)
for(int j=0;j<=100;j++)
for(int k=0;k<=100;k++)
for(int x=0;x<=100;x++)
f[i+j+k+x]=max(f[i+j+k+x],g[i]+g[j]+g[k]+g[x]);
int _;qr(_); while(_--) {
int n;qr(n);
printf("%.1lf\n",f[n]);
}
return 0;
}
实际上,每个绩点取最低分数即可.复杂度可以降至: .
直接 dp.
int f[N][N],n,m;
int main() {
n=1000;
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
f[i][j]=max(f[i-1][j],f[i][j-1])+(gcd(i,j)==1);
int _;qr(_); while(_--) {
qr(n); qr(m);
pr2(f[n][m]);
}
return 0;
}
恶心的语文题.
直接枚举城市建在哪里,然后每次把新人贪心安排在最大的点即可.
普及一个小小技巧: 和 是在整数运算上是不一样的.
,是相当于 .
而 ,对于非负整数 ,则相当于 ,但是对于负数则为 .
本质上是把小数部分舍去了.
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<cstdlib>
#include<vector>
#define ll long long
using namespace std;
const int N=505;
int d[20];
int cnt[5],n,a[N][N];
bool pd(int x,int y){return 1<=x&&x<=n&&1<=y&&y<=n;}
int calc(int x,int y)
{
int ans=0,s=a[x][y];
memset(cnt,0,sizeof(cnt));
for(int i=3;i>=-3;--i)
{
int w=3-abs(i);
for(int j=-w;j<=w;++j)
{
if(pd(x+i,y+j))++cnt[a[x+i][y+j]];
}
}
cnt[s]--;
int tot=1,sum=0;
while(tot<9) {
sum+=s; ans++;
if(d[tot]<=sum) {
tot++;
for(int i=3;i;i--)
if(cnt[i]) {
s+=i;
cnt[i]--;
break;
}
}
}
return ans;
}
int main()
{
int t;scanf("%d",&t);
for(int i=1;i<=9;i++)d[i]=8*i*i;
while(t--)
{
int x,y;scanf("%d%d%d",&n,&x,&y);
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
scanf("%d",&a[i][j]);
int ans=0x3f3f3f3f;
for(int i=1;i<=n;i++)
{
for(int j=1;j<=n;j++)
{
int wd=abs(x-i)+abs(y-j);
ans=min(ans,calc(i,j)+((wd-1)>>1)+1);
}
}
printf("%d\n",ans);
}
return 0;
}
简单概率题
因为 是递增的,所以同层不会有两个黑同时连在一个上层黑.(对于两层 相等的情况,只有一种情况是不满足的,但是算概率的时候我们是算长度占总长度的,所以可以忽略这种情况).所以这是一个森林,森林的连通块数=点数-边数.
我们单独考虑一个黑块是否和上一层的黑块不合并.
不合并的概率为 (考虑上面那块在 的长度上移动,取不相邻时的开头长度/总长度)
由于这一层有 个黑,所以这层的总贡献为 .
特别的,对于第一层开始有 个,所以 .
int n,a[N];
ll ans,inv=(mod+1)/2;
int main() {
int _;qr(_); while(_--) {
qr(n); ans=0;
for(int i=1;i<=n;i++) qr(a[i]);
ans=(a[1]+a[n])/2*inv%mod;
pr2(ans);
}
return 0;
}
肯定贪心选择权值小的,然后我们枚举一下覆盖次数,计算一下每次的合法格点数.
复杂度为 .
ll l[4],k,ans;
ll f(ll x,ll y) {//边长,曼哈顿距离
if(x>=y) {
if(!y) return 1;
return 4*y;
}
else return 4*max(2*x-y+1,0LL);
}
int main() {
int _;qr(_); while(_--) {
for(int i=0;i<4;i++) qr(l[i]);
qr(k); ans=0;
for(int i=0;k;i++) {//枚举贡献
ll t=0;
for(int j=1;j<=4;j++) if(i%j==0) {//枚举覆盖次数
int k=i/j;
t+=f(l[4-j],k);
if(j!=4) t-=f(l[3-j],k);//容斥
}
t=min(t,k); k-=t;
ans+=t*i;
}
pr2(ans);
}
return 0;
}
网络流好题.
虽然考试时候也想到网络流,但是实在太劣了, 二分, 暴力匹配,其实单做一次就会T.
正解十分巧妙,定义 表示 时刻内 这个状态(对窗户进行状压,1表示有这个窗户)能到达的格点数,这个可以通过 的预处理实现.
然后对于一个时间 ,这样构建流图:
这个的点数只有 ,所以可以轻松跑.
#include<bits/stdc++.h>
#define pi pair<int,int>
#define fi first
#define se second
using namespace std;
const int N=2005,M=8,inf=2e9;
void qr(int &x) {scanf("%d",&x); }
namespace flow {
const int N=1<<7,M=N*30;
int st,ed,d[N],c[N],q[N];
struct edge{int y,next,c;} a[M]; int len,last[N],cur[N];
void clear() {memset(last,0,sizeof(int[ed+1])); len=1;}
void ins(int x,int y,int c) {a[++len]=(edge){y,last[x],c}; last[x]=len;}
void add(int x,int y,int c) {ins(x,y,c); ins(y,x,0);}
void bfs() {
for(int i=0;i<=ed;i++) c[i]=d[i]=0,cur[i]=last[i];
int l,r; q[l=r=1]=ed; ++c[d[ed]=1];
for(int x=ed;l<=r;x=q[++l])
for(int k=last[x],y;k;k=a[k].next)
if(!d[y=a[k].y]) {++c[d[y]=d[x]+1]; q[++r]=y;}
}
int dfs(int x,int f) {
if(x==ed) return f;
int s=0,t;
for(int &k=cur[x],y,z;k;k=a[k].next) {
y=a[k].y; z=min(a[k].c,f-s);
if(z&&d[y] == d[x]-1) {
s += t = dfs(y,z);
a[k].c -= t; a[k^1].c += t;
if(s == f) return s;
}
}
if(!--c[d[x]]) d[st]=ed+1;
++c[++d[x]]; cur[x]=last[x]; return s;
}
int dicnic() {
int s=0; bfs();
while(d[st]<=ed) s+=dfs(st,inf);
return s;
}
}
int n,m,k,x[M],y[M],z[M],f[N][1<<M];
bool check(int x) {
int st=(1<<k)+k,ed=st+1;
flow::st=st; flow::ed=ed; flow::clear();
for(int i=0;i<k;i++) flow::add(st,i,z[i]);
for(int i=0;i<(1<<k);i++) {
flow::add(i+k,ed,f[x][i]);
for(int j=0;j<k;j++) if(i>>j&1)
flow::add(j,i+k,inf);
}
return flow::dicnic()==n*m;
}
int main() {
int T; qr(T); while(T--) {
memset(f,0,sizeof f);
qr(n); qr(m); qr(k);
for(int i=0;i<k;i++) qr(x[i]),qr(y[i]),qr(z[i]);
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++) {
vector<pi> cur(k);
for(int t=0;t<k;t++)
cur[t]=make_pair(abs(x[t]-i)+abs(y[t]-j),t);
sort(cur.begin(),cur.end());
for(int t=0,tot=0;t<k;t++) {
tot |= 1 << cur[t].se;
f[cur[t].fi][tot]++;
if(t < k - 1) f[cur[t+1].fi][tot]--;
}
}
int l=0,r=n+m,mid;
for(int i=1;i<=r;i++)
for(int j=0;j<(1<<k);j++)
f[i][j] += f[i-1][j];
if(!check(r)) puts("-1");
else {
while(l<r) {
mid=(l+r)/2;
if(check(mid)) r=mid;
else l=mid+1;
}
printf("%d\n",l);
}
}
return 0;
}
莫比乌斯反演好题.(数学推导能力又下降了…
上面有些向下取整忽略掉了,希望不影响阅读.
设 ,则我们需要 预处理 的前缀和, 预处理约数和.
的复杂度是 的,总共调用G的复杂度为
#include<map>
#include<set>
#include<ctime>
#include<queue>
#include<cmath>
#include<cstdio>
#include<vector>
#include<string>
#include<bitset>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<functional>
#define lc (x<<1)
#define rc (x<<1|1)
#define gc getchar()//(p1==p2&&(p2=(p1=buf)+fread(buf,1,size,stdin),p1==p2)?EOF:*p1++)
#define mk make_pair
#define pi pair<int,int>
#define pb push_back
#define IT iterator
#define SZ(a) ((int)a.size())
#define all(a) a.begin(),a.end()
using namespace std;
typedef long long ll;
typedef long double ld;
typedef unsigned long long ull;
const int N=1e6+10,size=1<<20,mod=1e9+7,inv=(mod+1)/2;
//char buf[size],*p1=buf,*p2=buf;
template<class o> void qr(o &x) {
char c=gc; x=0; int f=1;
while(!isdigit(c)){if(c=='-')f=-1; c=gc;}
while(isdigit(c)) x=x*10+c-'0',c=gc;
x*=f;
}
template<class o> void qw(o x) {
if(x/10) qw(x/10);
putchar(x%10+'0');
}
template<class o> void pr1(o x) {
if(x<0)x=-x,putchar('-');
qw(x); putchar(' ');
}
template<class o> void pr2(o x) {
if(x<0)x=-x,putchar('-');
qw(x); puts("");
}
//math
ll mult(ll a,ll b,ll p) {
a=(a%p+p)%p; b=(b%p+p)%p;
ll c=(ld)a*b/p;
return a*b-c*p;
}
ll gcd(ll a,ll b) {return !a?b:gcd(b%a,a);}
ll lcm(ll a,ll b) {return a/gcd(a,b)*b;}
ll power(ll a,ll b=mod-2) {
ll c=1;
while(b) {
if(b&1) c=c*a%mod;
b /= 2; a=a*a%mod;
}
return c;
}
ll Power(ll a,ll b=mod-2) {
ll c=1;
while(b) {
if(b&1) c=mult(c,a,mod);
b /= 2; a=mult(a,a,mod);
}
return c;
}
int prime[N],tot,mu[N],g[N]; bool v[N];
void upd(int &x) {x-=(x>=mod)*mod; x+=x>>31&mod;}
void get(int x) {
mu[1]=1;
for(int i=2;i<=x;i++) {
if(!v[i]) prime[++tot]=i,mu[i]=-1;
for(int j=1,k;(k=i*prime[j])<=x;j++) {
v[k]=1;
if(i%prime[j]) mu[k]=-mu[i];
else break;
}
}
for(int i=1;i<=x;i++) {
upd(mu[i]=mu[i-1]+mu[i]*i);
for(int j=i;j<=x;j+=i) upd(g[j]+=i);
}
for(int i=1;i<=x;i++) upd(g[i]+=g[i-1]);
}
ll calc(ll n) {
if(n<N) return g[n];
ll s=0;
for(ll l=1,r;l<=n;l=++r) {
r=n/(n/l);
s+= (r-l+1)%mod*((r+l)%mod)%mod*inv%mod*((n/l)%mod)%mod;
}
return s%mod;
}
int main() {
get(N-1);
int _;qr(_); while(_--) {
ll n,ans=0;qr(n);
for(ll l=1,r;l*l<=n;l=++r) {
r=l;
while(n/(r+1)/(r+1)==n/l/l) ++r;
ans += (mu[r]-mu[l-1]+mod) * calc(n/l/l) % mod;
}
pr2(ans%mod);
}
return 0;
}