SRM 500 250pts
答案一定是被选次数最多的人被选的概率,模拟第一次后的结果,考虑剩下的个数。以后每次剩下的都是用n%当前的个数。
#include <bits/stdc++.h>
using namespace std;
#define N 510
int val[N];
class MafiaGame
{
public:
double probabilityToLose(int n,vector<int>a)
{
int mx=0;double ret=1;
for(int i=0;i<a.size();i++)
val[a[i]]++,mx=max(mx,val[a[i]]);
int tot=n-a.size(),cnt=0;
for(int i=0;i<n;i++)
if(val[i]<=mx-1)
tot-=mx-1-val[i],val[i]=mx-1;
else cnt++;
if(tot>0)cnt+=tot;
if(mx==0)cnt=n;
while(cnt!=1)
{
if(n%cnt==0)return 0;
ret=ret*(n%cnt)/cnt;
cnt=n%cnt;
}
return ret;
}
}tmp;
SRM 500 500pts
搜搜搜!!!! 扒了题解的代码,感觉还是很妙的,避免精度误差。
由于给出的坐标都是整数,所以边界上递归下去的并不多。
#include <bits/stdc++.h>
using namespace std;
#define N 510
int val[N];
class FractalPicture
{
double cal(int deep,int x1,int x2,int y1,int y2)
{
x1=max(x1,-27);x2=min(x2,27);
y1=max(y1,0);y2=min(y2,81);
if(x1>x2||y1>y2)return 0;
if(x1==-27&&x2==27&&y1==0&&y2==81)
return deep*54+27;
if(deep==1)
{
if(x1>0||x2<0)return 0;
return y2-y1;
}
double ret=0;
if(x1<=0&&x2>=0&&y1<=54)
ret=min(y2,54)-y1;
return ret+1.0/3*(
cal(deep-1,x1*3,x2*3,(y1-54)*3,(y2-54)*3)+
cal(deep-1,(y1-54)*3,(y2-54)*3,x1*3,x2*3)+
cal(deep-1,(y1-54)*3,(y2-54)*3,-x2*3,-x1*3));
}
public:
double getLength(int x1,int y1,int x2,int y2)
{return cal(500,x1,x2,y1,y2);}
}tmp;
SRM 500 1000pts
1,2,4,8,6,3,9的个数不固定,手动枚举2,4,8,9的个数可以确定1,3的个数。
/*
注 意 枚 举 顺 序!!!!!!!!!!!!!!!!!!!!!!
妈蛋枚举的时候顺序不对搞出负数本机和tc测的不一样调了半天我会乱说?
(手动注释)*/
对于每一数字单独计算个数,设i出现的次数为ai,那么考虑某个ai 出现在指定的一位,那么它对答案的贡献为:
(n−1)!∗ai!a1!a2!...a10!∗(ai−1)!∗i
预处理一个ten[i]=10i+10i−1+....+1 就可以计算该情况下每个数字的贡献了。
#include <bits/stdc++.h>
using namespace std;
#define mod 500500573
#define ll long long
#define N 2600
ll ten[N],jc[N],njc[N];
int cnt[21];
ll qpow(ll x,ll y)
{
ll ret=1;
while(y)
{
if(y&1)ret=ret*x%mod;
x=x*x%mod;y>>=1;
}
return ret;
}
class ProductAndSum
{
public:
int getSum(int p2,int p3,int p5,int p7,int sum)
{
ll ret=0;
ten[0]=1;jc[0]=njc[0]=1;
for(int i=1;i<=sum;i++)jc[i]=jc[i-1]*i%mod;
njc[sum]=qpow(jc[sum],mod-2);
for(int i=sum-1;i>=1;i--)njc[i]=njc[i+1]*(ll)(i+1)%mod;
for(int i=1;i<=sum;i++)ten[i]=(ten[i-1]*10ll)%mod;
for(int i=1;i<=sum;i++)ten[i]=(ten[i]+ten[i-1])%mod;
for(cnt[2]=0;cnt[2]<=p2;cnt[2]++)
for(cnt[4]=0;cnt[4]*2+cnt[2]<=p2;cnt[4]++)
for(cnt[8]=0;cnt[8]*3+cnt[4]*2+cnt[2]<=p2;cnt[8]++)
{
cnt[6]=p2-cnt[2]-cnt[8]*3-cnt[4]*2;
for(cnt[9]=0;cnt[6]+cnt[9]*2<=p3;cnt[9]++)
{
cnt[5]=p5;cnt[7]=p7;
cnt[3]=p3-cnt[6]-cnt[9]*2;
cnt[1]=sum;
for(int w=2;w<=9;w++)
cnt[1]-=cnt[w]*w;
if(cnt[1]<0)continue;
int tot=0;ll mul=1;
for(int w=1;w<=9;w++)
tot+=cnt[w],mul=mul*njc[cnt[w]]%mod;
mul=mul*jc[tot-1]%mod;
for(int w=1;w<=9;w++)
ret=(ret+ten[tot-1]*mul%mod*jc[cnt[w]]%mod*njc[cnt[w]-1]%mod*w%mod)%mod;
}
}
return ret;
}
}tmp;
SRM 501 250pts
设f[i][j] 表示走i步A,j步B的最大得分,g[i][j] 表示最小得分,dp一下就好了。
#include <bits/stdc++.h>
using namespace std;
double f[52][52],g[52][52];
class FoxPlayingGame
{
public:
double theMax(int A,int B,int v1,int v2)
{
f[0][0]=0;
for(int i=0;i<=A;i++)
for(int j=0;j<=B;j++)
{
if(i||j)f[i][j]=-1e100,g[i][j]=1e100;
if(i)
{
f[i][j]=max(f[i][j],f[i-1][j]+(double)v1/1000.0);
g[i][j]=min(g[i][j],g[i-1][j]+(double)v1/1000.0);
}
if(j)
{
f[i][j]=max(f[i][j],f[i][j-1]*v2/1000.0);
g[i][j]=min(g[i][j],g[i][j-1]*v2/1000.0);
f[i][j]=max(f[i][j],g[i][j-1]*v2/1000.0);
g[i][j]=min(g[i][j],f[i][j-1]*v2/1000.0);
}
}
return f[A][B];
}
}tmp;
SRM 501 500pts
设f[i][S][j][k] 表示到第i个点,总和为S,第i-1个点的值为j,第i-2个点是否大于第i-1个点的方案数。
#include <bits/stdc++.h>
using namespace std;
#define mod 1000000007
int f[41][1610][41][2],n;
class FoxAverageSequence
{
public:
int theCount(vector<int> a)
{
n=a.size();
f[0][0][0][0]=1;
for(int i=0;i<n;i++)
for(int j=0;j<=i*40;j++)
for(int k=0,t;k<=40;k++)
{
if((t=a[i])!=-1)
{
if(i==0||t<=j/i)
{
if(t<k)(f[i+1][j+t][t][1]+=f[i][j][k][0])%=mod;
else
{
(f[i+1][j+t][t][0]+=f[i][j][k][0])%=mod;
(f[i+1][j+t][t][0]+=f[i][j][k][1])%=mod;
}
}
}
else for(t=0;t<=40;t++)
{
if(i!=0&&t>j/i)break;
if(t<k)(f[i+1][j+t][t][1]+=f[i][j][k][0])%=mod;
else
{
(f[i+1][j+t][t][0]+=f[i][j][k][0])%=mod;
(f[i+1][j+t][t][0]+=f[i][j][k][1])%=mod;
}
}
}
int ans=0;
for(int i=0;i<=n*40;i++)
for(int j=0;j<=40;j++)
for(int k=0;k<=1;k++)
(ans+=f[n][i][j][k])%=mod;
return ans;
}
}tmp;
SRM 501 1000pts
设f[i][j] 表示到第i个点,左右走了j步的最小花费,把坐标相同的放在一起,
按纵坐标排序,把横坐标相同的放在一起搞。
可以用f[i′][j−abs(x[i′],x[i])] 更新f[i][j]
把绝对值拆开,对于x坐标小于当前x坐标的点f[i][j+x[i]]=max(f[i′][j+x[i′]])
对于x坐标大于当前x坐标的点f[i][j−x[i]]=max(f[i′][j−x[i′]])
这个东西可以拿树状数组维护。这样就非常妙了。
对于横坐标相同的从两边各更新一遍,最后合在一起统计一下。
//虽然说tc里dp多,为什么一场都是dp呀。。。
#include <bits/stdc++.h>
using namespace std;
#define mod 1000000007
#define ll long long
#define N 1100
int w,h,n,m,v,tx,ty;
struct node
{
int x,y,v;
friend bool operator < (const node &r1,const node &r2)
{
if(r1.y==r2.y)return r1.x<r2.x;
return r1.y<r2.y;
};
}a[N],tmp[N];
int f[N][N],t[N][N];
struct diw_tree
{
int tr[N];
void insert(int x,int y)
{
x++;
for(int i=x;i<=w+5;i+=i&-i)
tr[i]=max(tr[i],y);
}
int query(int x)
{
x++;int ret=0;
for(int i=x;i;i-=i&-i)
ret=max(ret,tr[i]);
return ret;
}
}A[N<<1],B[N<<1];
class FoxSearchingRuins
{
ll solve()
{
int tn=0;a[0].x=-1;
for(int i=1;i<=n;i++)
{
if(a[i].x!=a[i-1].x||a[i].y!=a[i-1].y)tn++;
tmp[tn].x=a[i].x;tmp[tn].y=a[i].y;tmp[tn].v+=a[i].v;
}
n=tn;for(int i=1;i<=n;i++)a[i]=tmp[i];
sort(a+1,a+1+n);
for(int l=1,r;l<=n;l=r+1)
{
for(r=l;r<=n&&a[r].y==a[l].y;r++);r--;
for(int i=l;i<=r;i++)
{
for(int j=a[i].x;j-a[i].x<=m;j++)
f[i][j-a[i].x]=max(f[i][j-a[i].x],B[j].query(w-a[i].x)+a[i].v);
for(int j=-a[i].x;j+a[i].x<=m;j++)
f[i][j+a[i].x]=max(f[i][j+a[i].x],A[j+w].query(a[i].x)+a[i].v);
}
for(int i=l;i<=r;i++)
for(int j=0;j<=w;j++)t[i][j]=f[i][j];
for(int i=l+1;i<=r;i++)
for(int j=a[i].x-a[i-1].x;j<=w;j++)
t[i][j]=max(t[i][j],t[i-1][j-(a[i].x-a[i-1].x)]+a[i].v);
for(int i=r-1;i>=l;i--)
for(int j=a[i+1].x-a[i].x;j<=w;j++)
f[i][j]=max(f[i][j],f[i+1][j-(a[i+1].x-a[i].x)]+a[i].v);
for(int i=l;i<=r;i++)
for(int j=0;j<=w;j++)f[i][j]=max(f[i][j],t[i][j]);
for(int i=l;i<=r;i++)
{
for(int j=a[i].x;j-a[i].x<=m;j++)
B[j].insert(w-a[i].x,f[i][j-a[i].x]);
for(int j=-a[i].x;j+a[i].x<=m;j++)
A[j+w].insert(a[i].x,f[i][j+a[i].x]);
}
}
ll ans=1ll<<61;
for(int i=1;i<=n;i++)
for(int j=0;j<=m;j++)
if(f[i][j]>=v)
{
ans=min(ans,(ll)tx*j+(ll)ty*a[i].y);
}
return ans==1ll<<61 ? -1:ans;
}
public:
ll theMinTime(int W, int H, int jewelCount, int LR, int goalValue, int timeX, int timeY, vector <int> seeds)
{
w=W;h=H;n=jewelCount;
m=LR;v=goalValue;tx=timeX;ty=timeY;
a[1].x=((ll)seeds[1]*seeds[0]+seeds[2])%W;
a[1].y=((ll)seeds[4]*seeds[3]+seeds[5])%H;
a[1].v=((ll)seeds[7]*seeds[6]+seeds[8])%seeds[9];;
for(int i=2;i<=n;i++)
{
a[i].x=((ll)seeds[1]*a[i-1].x+seeds[2])%W;
a[i].y=((ll)seeds[4]*a[i-1].y+seeds[5])%H;
a[i].v=((ll)seeds[7]*a[i-1].v+seeds[8])%seeds[9];
}
return solve();
}
}cls;
SRM 502 250pts
如果有其他字符串是当前字符串的后缀就去掉当前字符串,否则加上概率就行了。
#include <bits/stdc++.h>
using namespace std;
int n;
double per[11];
int cal(string x,string y)
{
if(x.size()<y.size())return 0;
for(int i=y.size();i>=1;i--)
if(x[x.size()-i]!=y[y.size()-i])return 0;
return 1;
}
int cmp(string x,string y)
{
if(x.size()==y.size())
return x<y;
return x.size()<y.size();
}
class TheLotteryBothDivs
{
public:
double find(vector <string> a)
{
per[0]=1;double ans=0;
for(int i=1;i<=10;i++)per[i]=per[i-1]/10;
n=a.size();
sort(a.begin(),a.end(),cmp);
for(int i=0;i<n;i++)
{
cout<<a[i]<<endl;
int flag=0;
for(int j=0;j<i;j++)
if(cal(a[i],a[j]))
{flag=1;break;}
if(!flag)ans+=per[a[i].size()];
}
return ans;
}
}cls;
SRM 502 500pts
贪心,按pointsPerMinuterequiredTime 从小到大排序,最后选出的做的题一定是按这个顺序排序。官网上有证明,大概是考虑交换相邻两个之后的情况。
排序之后dp,设f[i][j] 表示现在做到第i个题,剩余时间为j的最大得分。
#include <bits/stdc++.h>
using namespace std;
#define ll long long
struct node
{
int v,dec,req;
friend bool operator < (const node &r1,const node &r2)
{return (ll)r1.dec*r2.req>(ll)r2.dec*r1.req;};
}a[51];
int f[51][110000],n;
class TheProgrammingContestDivOne
{
public:
int find(int T, vector <int> v, vector <int> dec, vector <int> req)
{
n=v.size();
for(int i=1;i<=n;i++)
{
a[i].v=v[i-1];
a[i].dec=dec[i-1];
a[i].req=req[i-1];
}
sort(a+1,a+1+n);
f[0][T]=0;
for(int i=1;i<=n;i++)
for(int j=0;j<=T;j++)
{
f[i][j]=f[i-1][j];
if(j+a[i].req<=T)
f[i][j]=max((ll)f[i][j],(ll)f[i-1][j+a[i].req]+a[i].v-(ll)(T-j)*a[i].dec);
}
int ans=0;
for(int i=0;i<=T;i++)ans=max(ans,f[n][i]);
return ans;
}
}cls;
SRM 502 1000pts
这题好神呀!!
设f[d][k][a] 为 方程x1+x2+....+xk−1+axk≡0(modd) 的解的个数。其中x1到xk 为 [0,n) 内的整数。
设sum=x1+x2+....+xk−1 ,g=gcd(a,d) 。
那么方程有解的充要条件为sum%g=0 且在[0,d) 内的解的个数有g 个。那么在
所以这部分答案为f[g][k−1][1]∗g∗nd
由可能出现xk 与其他x相等的情况,所以需要减去f[g][k−1][a+1]∗(k−1), 因为每一个都重复出现了k−1次。
因此f[d][k][a]=f[g][k−1][1]∗g∗nd−f[g][k−1][a+1]∗(k−1)
第一维只能是n的约数,第三维只能是1或K+1-k。
用map存一下状态,记忆化搜一下。
#include <bits/stdc++.h>
using namespace std;
#define mod 1000000007
#define ll long long
map<int,int>ma[1100][2];
int n,k1;
int gcd(int x,int y)
{return y==0 ? x:gcd(y,x%y);}
int F(int d,int k,int a)
{
if(k==0)return 1;
int a1=a==1 ? 0:1;
if(ma[k][a1].count(d))return ma[k][a1][d];
int g=gcd(a,d);
ma[k][a1][d]=((ll)F(g,k-1,1)*g%mod*(n/d)%mod-(ll)F(d,k-1,(a+1)%d)*(k-1)%mod+mod)%mod;
return ma[k][a1][d];
}
int qpow(int x,int y)
{
int ret=1;
while(y)
{
if(y&1)ret=(ll)ret*x%mod;
x=(ll)x*x%mod;y>>=1;
}
return ret;
}
class TheCowDivOne
{
public:
int find(int N,int K)
{
n=N;k1=K+1;
int ans=F(N,K,1);
int jc=1;
for(int i=1;i<=K;i++)jc=(ll)jc*i%mod;
return (ll)ans*qpow(jc,mod-2)%mod;
}
}cls;
博客详细介绍了作者在TopCoder SRM 500, 501, 502三场比赛中遇到的题目,并对各个分值段的问题进行了分析和解答思路的分享。涉及动态规划、模拟、贪心等算法,包括概率计算、坐标处理、状态转移等技巧。"
122931606,7800548,Python绘制人口金字塔图:数据可视化详解,"['Python', '数据分析', '数据可视化']
397

被折叠的 条评论
为什么被折叠?



