B. Vaccination
思路
判断可以用一个疫苗的话不好搞,所以可以从什么要开一个新的疫苗入手
- 如果之前没有打开疫苗的话
- 之前的疫苗已经用完
- 轮到的这个人不能和之前的一起用这个疫苗
代码
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 2e5+10;
int p[N],hh,tt;
int n,k,d,w;
int a[N];
int main()
{
int t;
cin>>t;
while(t--)
{
int sum=0;
hh=tt=0;
cin>>n>>k>>d>>w;
for(int i=1;i<=n;i++)
{
cin>>a[i];
if(tt-hh>=k||tt==0||a[p[hh]]+w<a[i]-d)
{
tt=0,sum++,p[tt++]=i;
//cout<<i;
}
else p[tt++]=i;
}
cout<<sum<<endl;
}
}
C. Pull Your Luck
思路
注意到 n的范围和p范围,所以可以遍历一遍所有的n而不能遍历所有的p,那就遍历所有一遍n,再分析p和n关系
如果在1~n中没有有效答案,再进行分类讨论
- 如果 n为奇数的话 n ! = ( n + 1 ) ∗ n / 2 n! =(n+1)*n/2 n!=(n+1)∗n/2 ( n + 1 ) (n+1) (n+1)肯定可以整除2,所有 n ! m o d n = = 0 n!{\bmod}n==0 n!modn==0所以每经过n次都会回归原点,也就是说n后面的可以不用判断了
- 如果n为偶数 n ! = ( n / 2 ) ∗ n + n / 2 n!=(n/2)*n+n/2 n!=(n/2)∗n+n/2所以只要考虑 n / 2 n/2 n/2就行了
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 2e5+10;
int minmli[N];
int main()
{
int t;
cin>>t;
while(t--)
{
int n,x,p;
cin>>n>>x>>p;
int sum=0,anserw=(n-x)%n;
bool fl=false;
for(int i=1;i<=min(n,p);i++)
{
sum=(sum+i)%n;
minmli[i]=sum;
if(sum==anserw)fl=true;
}
if(n%2==0)
for(int i=1;i<=min(n,p-n);i++)
{
if((minmli[i]+n/2)%n==anserw)fl=true;
}
//cout<<anserw;
if(fl)puts("YES");
else puts("NO");
}
}
D. Accommodation
思路
考虑最少,就是看能有多少个 “11”就行了,直接遍历一遍就行
考虑最多,就是看能有多少个“10”,“01”,“00”就行直接dp,一层for就行
两个没有互相影响,且遍历顺序一样所以一起
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 5e5+10;
int m,n;
int l=0,zi=0,zu=0,minsum=0,maxsum;
int f[N];
int main()
{
scanf("%d%d",&n,&m);
int a=m/4,b=m/2,tem,tem1;
for(int tt=1;tt<=n;tt++)
{
l=0,zi=0,zu=0;
for(int i=1;i<=m;i++)
{
scanf("%1d",&tem);
if(i==1)f[i]=0;
else
{
f[i]=f[i-1];
if((tem&tem1)!=1)
{
f[i]=max(f[i],f[i-2]+1);
//cout<<i<<endl;
}
}
if(tem==1)l++,zi++;
else zi=0;
if(zi==2)zu++,zi=0;
tem1=tem;
}
//cout<<f[3]<<endl;
minsum+=min(zu,a)+l-2*min(zu,a);
maxsum+=l-max(0,a-f[m]);
}
printf("%d %d\n",minsum,maxsum);
}
E. Routing
思路
题目意思很长,但其实就是就是找是否存在一个环,这个环上的点只出现一次,并且所有点要么组成这个环,要么和环上的点直接联系,找环可以可以借鉴哈密顿路径的写法,
f
[
i
]
[
j
]
f[i][j]
f[i][j]表示从i位次最低的点为起点,经过的点集为i,最终到达j的可能性,如果存在f[i][j]==true,并且存在i位次最低的点到j的路就存在环
注意只有一条的边的两个点也算环,单独一个点不算。
#include <iostream>
#include <cstring>
#include <algorithm>
#include <map>
using namespace std;
const int N = 20;
map<int,int> cf;
bool f[1<<N][N];
bool st[N][N];
int d[N];
int n,m;
bool cff[N];
bool cr[N];
bool fl=false;
int lowbit(int x) // 返回末尾的1
{
return x & -x;
}
bool check(int x)
{
//cout<<x<<endl;
memset(cff,0,sizeof cff);
int l=0;
for(int i=0;i<n;i++)if(x&(1<<i))cff[i]=true,l++;
for(int i=0;i<n;i++)
{
if(cff[i])continue;
for(int j=0;j<n;j++)
{
if(cff[j]&&st[i][j]){l++;break;}
}
}
if(l!=n)return false;
//cout<<x<<endl;
//if(l==n)return true;
fl=true;
for(int i=0;i<n;i++)
{
if(cff[i])continue;
for(int j=0;j<n;j++)
{
if(cff[j]&&st[i][j])
{
d[i]=j;
break;
}
}
}
int zz=-1,yy;
for(int i=0;i<n;i++)
{
if(f[x][i]&&st[cf[lowbit(x)]][i])zz=i;
}
d[zz]=cf[lowbit(x)];
x-=(1<<zz);
yy=zz;
//cout<<x;
while(x)
{
zz=-1;
for(int i=0;i<n;i++)
{
if(f[x][i]&&st[i][yy])zz=i;
}
d[zz]=yy;
x-=(1<<zz);
yy=zz;
}
return true;
}
int main()
{
cin>>n>>m;
for(int i=0;i<n;i++)cf[1<<i]=i;
for(int i=0;i<m;i++)
{
int a,b;
cin>>a>>b;
a--,b--;
st[a][b]=st[b][a]=true;
}
for(int i=0;i<n;i++)f[1<<i][i]=true;
for(int i=1;i<1<<n;i++)
{
for(int j=cf[lowbit(i)]+1;j<n;j++)
{
if(i&(1<<j))
{
for(int k=cf[lowbit(i)];k<n;k++)
{
if(st[k][j]&&(i-(1<<j))&(1<<k))
{
f[i][j]|=f[i-(1<<j)][k];
}
}
}
}
}
for(int i=0;i<1<<n;i++)
{
bool fl=false;
for(int j=0;j<n;j++)
{
if(f[i][j]&&st[cf[lowbit(i)]][j])fl=true;
}
if(fl&&check(i))break;
}
//if(check(6374))cout<<"kjf";
//for(int i=0;i<n;i++)cout<<d[i]+1<<" ";
//cout<<st[0][1];
if(fl)
{
puts("YES");
for(int i=0;i<n;i++)cout<<d[i]+1<<" ";
}
else puts("NO");
}
ps:搞了一下午。。。。