省赛之后终于又更新博客了,这两个星期的作业考试真是折腾的我够呛,有一大堆题目没有整理,还是慢慢整理吧。
Codeforces 87C Interesting Game
题意:一开始有一堆数量为n的石子,每次把其中的一堆石子分成任意堆,要求分成的堆数满足a[1]-a[2]=a[2]-a[3]=a[3]-a[4]......=a[k-1]-a[k]=1,其中k>=2,如果先手能赢,输出先手第一次分石子应分的最小堆数,否则输出-1.
这道题我找规律做的并不过。题解其实就是sg函数打表还是要好好在看看博弈了。
来自:https://blog.youkuaiyun.com/i1020/article/details/79824567
【思路】sg函数打表,求出其子状态的sg值。首先从3....n枚举石子数,内层再枚举当前可能分的堆数;假设当前分了m堆,这m堆中石子数量最少的为x个,又知当前m堆石子为等差数列,最小项为x,则可得当前m堆的石子总数量为(x-1)*m+(m*(m+1)/2);所以用当前总共的石子数量i-m*(m+1)/2的结果一定为m的倍数。然后通过其子状态的sg值异或得到当前状态的sg值即可。
const int N = 1e5+10;
int n,sg[N],mex[N];
int main()
{
scanf("%d",&n);
int ans = -1;
int cnt = 1;
for(int i = 3; i <= n; i ++)
{
for(int m=2;;m++)
{
int r=i-m*(m+1)/2;
if(r<0) break;
if(r%m) continue;
int g=0; //g表示其子状态的异或和
for(int j=1;j<=m;j++) g^=sg[r/m+j];
if(!g && i==n && ans < 0) ans = m;
mex[g] = cnt;
}
for(int j=0;;j++)
{
if(mex[j]!=cnt)
{
sg[i]=j;
cnt++;
break;
}
}
}
printf("%d\n",ans);
return 0;
}
Gym - 101532C
题意:给出一个数列,求任意两个数相加(ai+aj)%1e9+7求最大。
思路:我的思路是因为题目说ai<=1e9所以,ai+aj<=2e9,那么将数列中的数排下序依次拿出,那么ai+x<=1e9+7的数,和ai+x<=2e9,照两个最接近的数比最大值。相当于两个峰值(最多存在两个峰值)。还是看代码吧。(注意要判断二分得到的值是不是ai本身,否则要退一位取)
代码:
const ll mod=1e9+7;
struct node
{
ll val;
ll id;
}a[100005];
bool cmp(node s,node t)
{
if(s.val==t.val) return s.id<t.id;
return s.val<t.val;
}
ll n;
ll ans[100005];
ll search(ll begin,ll end,ll e)
{
ll mid,left=begin,right=end;
while(left<=right)
{
mid=(left+right)>>1;
if(a[mid].val>e) right=mid-1;
else left=mid + 1;
}
return right;
}
int main()
{
int T;
scanf("%d",&T);
while(T--)
{
scanf("%lld",&n);
for(int i=1;i<=n;i++)
{
scanf("%lld",&a[i].val);
a[i].id=i;
}
sort(a+1,a+1+n,cmp);
for(int i=1;i<=n;i++)
{
ll t=search(1,n,mod-a[i].val-1);
if(a[i].id==a[t].id) t--;
//cout<<t<<endl;
if(t!=0)
{
ans[a[i].id]=(a[t].val+a[i].val)%mod;
//cout<<ans[a[i].id]<<endl;
}
else ans[a[i].id]=0;
//cout<<ans[a[i].id]<<endl;
t=search(1,n,2*mod-a[i].val-1);
if(a[i].id==a[t].id) t--;
ans[a[i].id]=max(ans[a[i].id],(a[t].val+a[i].val)%mod);
}
for(int i=1;i<=n;i++) cout<<ans[i]<<" ";cout<<endl;
}
}
Gym - 101532J
题意:给出一个数列(a1,a2...an),求a1+a2+...an+(a1a2)+(a1a3)+....(a1a2a3...an)。
其实就是个组合数学公式(a1+1)(a2+1)...(an+1)。用递推式写出来就行了。
const ll mod=1e9+7;
ll a[100005];
ll dp[100005];
int main()
{
int T;
scanf("%d",&T);
while(T--)
{
ll n;
scanf("%lld",&n);
for(int i=1;i<=n;i++) scanf("%lld",&a[i]);
dp[1]=a[1]%mod;
for(int i=2;i<=n;i++)
{
dp[i]=(dp[i-1]+((dp[i-1]*a[i])%mod+a[i])%mod)%mod;
}
cout<<dp[n]<<endl;
}
}