#include
#define rep(i,a,b) for(int i=a;i<=(b);++i)
#define mem(a,x) memset(a,x,sizeof(a))
#define pb push_back
using namespace std;
typedef long long ll;
ll gcd(ll a,ll b) { return b?gcd(b,a%b):a;}
const int N=1e5+10;
int vis[N];
int cnt[4];
int num[4];
int c1,c2,c3,n;
int va,vb,vc;
bool flag=0;
int ans=0;
void cal(int &c,int s,int ty)
{
c=(c+s)%(n+1);
if(c==0) return ;
if(vis[c]==0)
{
cnt[ty]=0;
num[ty]++;
vis[c]=ty;
}
else if(vis[c]==ty) cnt[ty]++;
else
{
flag=1;
}
}
bool valid()
{
if(flag) return 1;
bool f=0;
for(int i=1;i<=3;++i)
{
if(cnt[i]<=num[i]) return 0;
}
return 1;
}
int main()
{
cin>>n>>va>>vb>>vc;
while(1)
{
cal(c1,va,1);
if(valid()) break;
ans++;
cal(c2,vb,2);
if(valid()) break;
ans++;
cal(c3,vc,3);
if(valid()) break;
ans++;
}
if(flag)
printf("%d\n",ans+1);
else printf("3000000000\n");
}
二分w加dp去check。
怎么dp呢?设dp[i][j]为前i个物品,使用了j个第一种,dp[i][j]个第二种的最小方案数。那么枚举j,可以得到转移方程:
k是a[i]-w时的上一个位置,
k0是a[i]-2*w的上一个位置。
#include
#define rep(i,a,b) for(int i=a;i<=(b);++i)
#define mem(a,x) memset(a,x,sizeof(a))
#define pb push_back
using namespace std;
typedef long long ll;
ll gcd(ll a,ll b) { return b?gcd(b,a%b):a;}
const int N=2e3+10;
const ll inf=0x3f3f3f3f3f3f3f;
int n;
int p,q;
ll a[N],b[N];
int lb;
ll dp[N][N];
int getid(ll x)
{
return upper_bound(b+1,b+1+lb,x)-b;
}
bool check(int w)
{
if (1ll*w*p+2ll*w*q>=a[n]-a[1]+1)
return 1;
memset(dp,inf,sizeof(dp));
dp[0][0]=0;
dp[1][0]=1;
dp[1][1]=0;
ll flag;
for(int i=2;i<=n;++i)
{
flag=inf;
int k=getid(a[i]-w)-1;
for(int j=0;j>n>>p>>q;
for(int i=1;i<=n;++i)
{
scanf("%lld",&a[i]);
b[i]=a[i];
}
sort(b+1,b+1+n);
sort(a+1,a+1+n);
lb=unique(b+1,b+1+n)-b-1;
int l=1,r=1e9;
int ans=0;
while(l<=r)
{
int mid=l+r>>1;
if(check(mid))
{
r=mid-1;
ans=mid;
}
else l=mid+1;
}
printf("%d",ans);
}
记录下斜率去下重就可以了
#include
using namespace std;
const int N = 5e5+100;
typedef long long ll;
ll gcd(ll a,ll b) { return b?gcd(b,a%b):a;}
pairhs[N];
int main()
{
ll x0,y0,r,x,y;
int n,ans=0;
scanf("%lld%lld%lld%d",&x0,&y0,&r,&n);
int m=0;
for(int i=1;i<=n;i++){
scanf("%lld%lld",&x,&y);
ll t1=y0-y,t2=x0-x;
if(t1*t1+t2*t2>r*r) continue;
ll t3 = gcd(t1,t2);
if(t3<0) t3=-t3;
t1/=t3;t2/=t3;
// printf("t1:%lld t2:%lld t3:%lld\n",t1,t2,t3);
hs[++m]=make_pair(t1,t2);
}
if(m==0)
{
printf("0\n");
return 0;
}
sort(hs+1,hs+1+m);
ll l=hs[1].first;r=hs[1].second;
ans=1;
for(int i=2;i<=m;++i)
{
if(l==hs[i].first&&r==hs[i].second) continue;
else
{
ans++;
l=hs[i].first;
r=hs[i].second;
}
}
printf("%d\n",ans);
}
换根dp搞一搞就可以了,不过有人的做法是直接求直径比较大小?很妙
#include
#define rep(i,a,b) for(int i=a;i<=(b);++i)
#define mem(a,x) memset(a,x,sizeof(a))
#define pb push_back
using namespace std;
typedef long long ll;
ll gcd(ll a,ll b) { return b?gcd(b,a%b):a;}
const int N=1e5+10,inf=0x3f3f3f3f;
int n,m;
vectorG[N],g[N],mx[N],mx1[N];
int dp[N],d[N];
int ans1,ans2;
void dfs1(int u,int fa)
{
//dp[u]=inf;
for(int v:G[u])
{
if(v==fa) continue;
dfs1(v,u);
dp[u]=max(dp[u],dp[v]);
}
dp[u]++;
}
void dfs2(int u,int fa)
{
dp[u]=0;
for(int v:G[u])
{
dp[u]=max(dp[u],dp[v]);
mx[u].push_back(dp[u]);
}
dp[u]++;
ans1=max(ans1,dp[u]);
int t1=-inf;
for(int i=G[u].size()-1;i>=0;--i)
{
dp[u]=t1;
int v=G[u][i];
if(i) dp[u]=max(dp[u],mx[u][i-1]);
dp[u]++;
t1=max(t1,dp[v]);
if(v!=fa) dfs2(v,u);
}
}
void dfs3(int u,int fa)
{
//d[u]=inf;
for(int v:g[u])
{
if(v==fa) continue;
dfs3(v,u);
d[u]=max(d[u],d[v]);
}
d[u]++;
}
dfs4(int u,int fa)
{
d[u]=0;
for(int v:g[u])
{
d[u]=max(d[u],d[v]);
mx1[u].push_back(d[u]);
}
d[u]++;
ans2=min(ans2,d[u]);
int t1=-inf;
for(int i=g[u].size()-1;i>=0;--i)
{
d[u]=t1;
int v=g[u][i];
if(i) d[u]=max(d[u],mx1[u][i-1]);
d[u]++;
t1=max(t1,d[v]);
if(v!=fa) dfs4(v,u);
}
}
int main()
{
cin>>n;
for(int i=1;i>m;
for(int i=1;i
由于这场是省赛模拟赛,所以这个题是队友写的,贴代码了。
#include
using namespace std;
int vis[10],n,f;
struct node{
int u,v;
}a[10],ans[10];
void dfs(int cur,int flag,int cnt){
if(f) return;
if(cnt==n+1&&!f){
for(int i=1;i<=n;i++){
cout<>n;
for(int i=1;i<=n;i++) cin>>a[i].u>>a[i].v;
for(int i=1;i<=n;i++){
memset(vis,0,sizeof vis);
vis[i]=1;
ans[1].u=i;
ans[1].v=0;
dfs(i,0,2);
memset(vis,0,sizeof vis);
vis[i]=1;
ans[1].u=i;
ans[1].v=1;
dfs(i,1,2);
}
}
题意:n堆物品,每堆,a[i]个石子,两个人,lowie先手,imitater后手,每次一个可以选择两个操作的其中一个。
1、从其中一堆拿走一个
2、所有堆各拿走一个,当一个堆中为空,不能执行该操作
拿掉最后一个的获胜。
做法:通过简单的观察,当前总数为奇数的时候是对自己是优势局面。由于自己是先手,那我可以通过微调使得自己永远是优势局面。
那么考虑总数为偶数的时候怎么利用自己是先手的优势来逆转局面?
当n为奇数的时候会发现自己无论都赢不了。
因为当你执行第二个操作,总数变成奇数,那么对面是优势局面,对面变成了先手且是优势局面,他可以通过自己最聪明的做法使得自己赢
当n为偶的时候才是有可能逆转局面的。
总数为偶数,执行第二种操作,总数还是偶数,成功的把偶数(劣势局面)转给对手,对手也可以通过相同的方法转给我,那么就变成拼谁最后使得不能执行第二个操作时的局势。当最小值为偶数,那么我不能把劣势转给对方,是我输;
最小值为奇数,我必赢。
代码:
#include
using namespace std;
typedef long long ll;
const int N=1e3+10;
ll a[N];
int main(){
ll mi=1e14;
ll sum=0;
int n;
cin>>n;
for(int i=1;i<=n;i++)
{
cin>>a[i];
sum+=a[i];
mi=min(mi,a[i]);
}
if(sum&1)printf("lowie");
else{
if(n&1)printf("imitater");
else {
if(mi%2==0)printf("imitater");
else printf("lowie");
}
}
}
include
using namespace std;
int main()
{
string s,ans="0";
int flag=0;
cin>>s;
for(int i=0;ians) ans=t;
}
}
}
if(flag) cout<
相邻的建图,数字一样建立一个虚点,虚点与这些点的权值是0,跑最短路就可以了,简单题
#include
using namespace std;
#define ll long long
ll input(){
ll x=0,f=0;char ch=getchar();
while(ch<'0'||ch>'9') f|=ch=='-',ch=getchar();
while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
return f? -x:x;
}
const int N=2e5+7;
#define clr(a,b) memset(a,b,sizeof a)
struct edge{ll v,w,next;}e[5*N];
int head[N],Cnt=0;
ll n,L,R,C,s,t;
ll a[N],b[N];
ll dis[N];
struct node{
ll u,d;
bool operator <(const node& rhs) const {return d>rhs.d;}
};
void Ins(ll u,ll v,ll w){
e[++Cnt]=(edge){v,w,head[u]},head[u]=Cnt;
}
priority_queue Q;
void Dijkstra(){
clr(dis,0x3f);
dis[s]=0;
Q.push((node){s,0});
while(!Q.empty()){
node fr=Q.top(); Q.pop();
ll u=fr.u,d=fr.d,v,w;
if(d!=dis[u]) continue;
for(int i=head[u];i;i=e[i].next){
if(dis[u]+(w=e[i].w)