A - A Funny Game(对称博弈)
A,B两人轮流从摆成一个圆的n个硬币中取硬币,可以取1个也可以取相邻的两个,最后谁无法取了算输,给出n,A先手,问谁最后会赢。
思路: 对称博弈。对于n<3,A必胜,但是n>=3时,A取过之后B都有办法取一定的数目来构造出中心对称,这样可以保证B取到最后的硬币,B必胜。
AC代码:
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <stack>
#include <vector>
#include <map>
#include <queue>
#include <cstring>
#include <cmath>
#include <set>
#include <iterator>
using namespace std;
typedef long long ll;
#define ios ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
#define INF 0x3f3f3f3f
//判断是否需要开ll!!!
//判断是否需要初始化!!!
const int mod=1e9+7;
int n;
int main()
{
// freopen("test.in","r",stdin);
// freopen("output.in", "w", stdout);
while(cin>>n)
{
if(n==0) break;
if(n>=3) cout<<"Bob"<<'\n';
else cout<<"Alice"<<'\n';
}
return 0;
}
os:一开始看错条件了WA了一发
D - Red and Blue(前缀和)
定义函数f(a),有两个数列r,b,将两数列按照原有的顺序合并,求最大的f(a)值。
思路:分别求两数列的前缀和,将最大的两个前缀和相加。
AC代码:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
#define ios ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
#define INF 0x3f3f3f3f
//判断是否需要开ll!!!
//判断是否需要初始化!!!
const int mod=1e9+7;
const int N=200;
int t,n,m,r[N],b[N];
int R[N],B[N];
int main()
{
// freopen("test.in","r",stdin);
// freopen("output.in", "w", stdout);
cin>>t;
while(t--)
{
memset(r,0,sizeof(r));
memset(R,0,sizeof(R));
memset(b,0,sizeof(b));
memset(B,0,sizeof(B));
cin>>n;
int maxn1=0,maxn2=0;
for(int i=1;i<=n;i++)
{
cin>>r[i];
R[i]=R[i-1]+r[i];
maxn1=max(maxn1,R[i]);
}
cin>>m;
for(int i=1;i<=m;i++)
{
cin>>b[i];
B[i]=B[i-1]+b[i];
maxn2=max(maxn2,B[i]);
}
cout<<maxn1+maxn2<<'\n';
}
return 0;
}
E - Expanding Rods(几何,二分)
给出升温后管道长度,求拱形高度。
思路: 铁棒弯曲后对应的圆的圆心在中线线上,且每一个R,就可以确定一个弧长,枚举R,求出对应的弧长l,不断逼近L,二分查找即可。部分推导:
AC代码:
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <stack>
#include <vector>
#include <map>
#include <queue>
#include <cstring>
#include <cmath>
#include <set>
using namespace std;
typedef long long ll;
#define ios ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
#define INF 0x3f3f3f3f
//判断是否需要开ll!!!
//判断是否需要初始化!!!
const int mod=1e9+7;
double L,n,C;
int main()
{
// freopen("test.in","r",stdin);
// freopen("output.in", "w", stdout);
while(cin>>L>>n>>C)
{
if(L<0&&n<0&&C<0) break;
double ans,l=0.0,r=0.5*L;
double L1=(1+n*C)*L;
while(r-l>1e-5)
{
ans=(l+r)/2;
double R=(4*ans*ans+L*L)/(8*ans);
if(2*R*asin(L/(2*R))<L1) l=ans;
else r=ans;
}
printf("%.3f\n",ans);
}
return 0;
}
os:还能这样做!一开始以为是按照正常数学公式推出来的,结果是二分试值?POJ好奇怪,double只能用/f输出
G - Teleporter(循环)
每一个城镇i都有一个通往a[i]的传送机,从第一个城镇开始,问传送k次被传送至哪个城镇。
思路:很容易看出传送是有循环的,先while循环找出传送循环长度,计算循环的余数即可。
AC代码:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
#define ios ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
#define INF 0x3f3f3f3f
//判断是否需要开ll!!!
//判断是否需要初始化!!!
const int mod=1e9+7;
const int N=2e5+5;
int n,a[N],c[N];
ll k;
int main()
{
// freopen("test.in","r",stdin);
// freopen("output.in", "w", stdout);
cin>>n>>k;
ll v=k;
for(int i=1;i<=n;i++) cin>>a[i];
int b=1,cnt=0;
map<int,int>mp;
while(k)
{
c[++cnt]=b;
if(mp[b]) break;
mp[b]++;
b=a[b];
k--;
}
if(k==0) cout<<b<<'\n';
else
{
for(int i=1;i<=cnt;i++)
{
if(c[i]==b)
{
pos=i;
break;
}
}
int dis=cnt-pos;
int Pos=(v+1-(pos-1))%dis;
if(Pos==0) Pos=dis;
cout<<c[pos+Pos-1]<<'\n';
}
return 0;
}
os:注意很多细节,计算循环长度边界是否需要加减!
I - Regular Bracket Sequence(思维)
给出一个包含(,),?的字符串,?可以被任意变为其他符号,问是否可以成为一个对称字符串。
思路:若字符串长度为奇数,那必不满足条件;若为偶数,只要开头不是),结尾不是(,都可以满足条件。
AC代码:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
#define ios ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
#define INF 0x3f3f3f3f
//判断是否需要开ll!!!
//判断是否需要初始化!!!
const int mod=1e9+7;
int t;
string s;
int main()
{
// freopen("test.in","r",stdin);
// freopen("output.in", "w", stdout);
cin>>t;
while(t--)
{
cin>>s;
int len=s.length();
if(len&1) cout<<"NO"<<'\n';
else
{
if(s[0]!=')'&&s[len-1]!='(') cout<<"YES"<<'\n';
else cout<<"NO"<<'\n';
}
}
return 0;
}
os:思维题
J - Ceil Divisions(思维)
给出1~n的序列,最多经过n+5次操作,使得数列变为由n-1个1和1个2组成的序列,问怎样操作。
思路: 很容易想到的一种思路是,对(i,i+1)进行操1那么我们就可以找,由于数据范围是2e5,求根号最多5次就可以了,把所有n求根号的数拿出来单独处理,剩下的按照(i,i+1)处理即可。
AC代码:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
#define ios ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
#define INF 0x3f3f3f3f
//判断是否需要开ll!!!
//判断是否需要初始化!!!
const int mod=1e9+7;
int t,n;
int main()
{
// freopen("test.in","r",stdin);
// freopen("output.in", "w", stdout);
cin>>t;
while(t--)
{
cin>>n;
int m=n-3;
int k=n;
vector<int> a;
a.push_back(k);
while(k>=3)
{
k=sqrt(k)+1;
a.push_back(k);
}
if(a[a.size()-1]!=2) a.push_back(2);
cout<<m+a.size()<<endl;
int i;
for(k=a.size()-2, i=3; i<n; i++)
{
if(a[k]==i) k--;
else
cout<<i<<" "<<i+1<<endl;
}
for(i=0; i<a.size()-1; i++)
{
cout<<a[i]<<" "<<a[i+1]<<endl;
cout<<a[i]<<" "<<a[i+1]<<endl;
}
}
return 0;
}
K - Building a Fence(判断循环)
给出长度为k宽为1的木板,给出地面高度,要满足条件构造篱笆,是否可以满足条件?
思路:设l,r为当前篱笆的最低高度和最高高度,每段篱笆的长度都为k,那么下一段的范围是[l-k+1,r+k-1],再加上地面高度a[i]因素,l=max(l-k+1,a[i]),r=min(r+k-1,a[i]+k-1),循环判断是否满足条件即可。
AC代码:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
#define ios ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
#define INF 0x3f3f3f3f
//判断是否需要开ll!!!
//判断是否需要初始化!!!
const int mod=1e9+7;
const int N=2e5+5;
int t,n,k;
int a[N];
int main()
{
// freopen("test.in","r",stdin);
// freopen("output.in", "w", stdout);
cin>>t;
while(t--)
{
cin>>n>>k;
for(int i=1;i<=n;i++) cin>>a[i];
bool flag=1;
int l=a[1],r=a[1];
for(int i=2;i<=n;i++)
{
l=max(l-k+1,a[i]);
r=min(r+k-1,a[i]+k-1);
if(l>r)
{
flag=0;
break;
}
}
if(a[n]<l||a[n]>r) flag=0;
cout<<(flag?"Yes":"No")<<'\n';
}
return 0;
}
L - : (Colon)(几何)
给出分针,时针长度,时间,求两针尖距离。
思路:知道时间可以得出两针夹角,余弦定理求对边长度。
AC代码:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
#define ios ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
#define INF 0x3f3f3f3f
//判断是否需要开ll!!!
//判断是否需要初始化!!!
const int mod=1e9+7;
int a,b,h,m;
int main()
{
// freopen("test.in","r",stdin);
// freopen("output.in", "w", stdout);
cin>>a>>b>>h>>m;
double ang=abs(5.5*m-30*h);
if(ang>180)
ang=360-ang;
//cout<<ang<<'\n';
ang=ang*3.1415926535898/180;
double q=a*a+b*b-cos(ang)*2*a*b;
printf("%.12lf\n",sqrt(q));
return 0;
}
os:计算角度公式可以记住。
M - Colorful Blocks(组合数学)
n个空格涂色,有m种颜色,最多允许k对两个相邻格子颜色相同,m种颜色不一定都用,求有多少种上色方案。
思路:枚举相邻的位置有i个,可以视作从n-1个(k,k+1)中选出i个出来,方案数为C(n-1,i),那么剩下的n-i个位置一定不相同,方案数为m*((m-1)^(n-i-1))。
AC代码:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
#define ios ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
#define INF 0x3f3f3f3f
//判断是否需要开ll!!!
//判断是否需要初始化!!!
const int mod=998244353;
const int N=2e6+5;
ll n,m,k;
ll fac[N],inv[N];
ll pmod(ll a,ll b)
{
ll ans=1%mod;
a%=mod;
while(b)
{
if(b&1)ans=ans*a%mod;
a=a*a%mod;
b>>=1;
}
return ans;
}
void init()
{
fac[0]=1;
for(int i=1;i<N;i++)
fac[i]=fac[i-1]*i%mod;
inv[N-1]=pmod(fac[N-1],mod-2);
for(int i=N-2;i>=0;i--)
inv[i]=(i+1)*inv[i+1]%mod;
}
ll C(ll n,ll m)
{
if(m<0||m>n)return 0;
return fac[n]*inv[m]%mod*inv[n-m]%mod;
}
int main()
{
// freopen("test.in","r",stdin);
// freopen("output.in", "w", stdout);
init();
cin>>n>>m>>k;
ll ans=0;
for(ll i=0;i<=k;i++)
{
ll t=C(n-1,i);
ll tt=m*pmod(m-1,n-i-1)%mod;
ans=(ans+t*tt%mod)%mod;
}
cout<<ans<<endl;
return 0;
}
若有错误请指教orzorz