G:
枚举两维+hash。
但更简单的做法是:直接暴力三维枚举,因为最多20个不能组成一个set。
#include
using namespace std;
typedef long long ll;
#define ls (o<<1)
#define rs (o<<1|1)
#define pb push_back
const double PI= acos(-1.0);
const int M = 1e3+7;
char s[M];
struct node{
int a[5];
}p[M];
unordered_mapmp;
unordered_mapvs;
int main()
{
int T;
scanf("%d",&T);
mp['n']=1;mp['w']=2;mp['h']=3;
mp['i']=1;mp['q']=2;mp['v']=3;
mp['o']=1;mp['t']=2;mp['p']=3;
mp['e']=1;mp['r']=2;mp['u']=3;
mp['*']=4;
for(int CA=1;CA<=T;CA++)
{
vs.clear();
int N;
scanf("%d",&N);
for(int i=1;i<=N;i++)
{
scanf("%s",s);
int n=strlen(s);
int tp=0;
for(int j=0;jv[5];
for(int k=1;k<=4;k++)v[k].clear();
for(int k=1;k<=4;k++)
{
v[k].pb(4);
if(p[i].a[k]==4||p[j].a[k]==4)
v[k].pb(1),v[k].pb(2),v[k].pb(3);
else
{
// if(i==1&&j==4)cout<
I:
一论游戏ai,bi,连边,建图。
显然环上所有点都可以选到。
而度数为1的点能选尽量选(因为选他只会影响到其连接的点,而选其连接的点会影响更多的点,得不偿失)
所以直接拓扑排序跑一边记录即可。
还有一个做法是:把边拆成点,如下图:
左部点表示离散后的每个数,右部点每个点都表示一条边,连接左部图两个点,显然每条边连的两个点只能选一个。
这个图的最大匹配刚好是答案。跑网络流二分图即可。(卡常,用一些优化和剪枝可以过,我T了,但有人过了)
给出拓扑排序的做法:
#include
using namespace std;
const int M=2e5+7;
int head[M],cnt=1;
struct EDGE{int to,nxt,w;}ee[M*2];
void add(int x,int y,int w){ee[++cnt].nxt=head[x],ee[cnt].w=w,ee[cnt].to=y,head[x]=cnt;}
struct no{
int x,y;
}p[M];
int sz,li[M];
int du[M];
int vs[M];
int main()
{
int T;
cin>>T;
for(int CA=1 ;CA<=T;CA++)
{
cnt=1;
sz=0;
memset(head,0,sizeof(head));memset(vs,0,sizeof(vs));
memset(du,0,sizeof(du));
int n;
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
int u,v;
scanf("%d%d",&u,&v);
li[++sz]=u;li[++sz]=v;
p[i]=no{u,v};
}
sort(li+1,li+1+sz);
sz=unique(li+1,li+1+sz)-(li+1);
for(int i=1;i<=n;i++)
{
int u=lower_bound(li+1,li+1+sz,p[i].x)-li;
int v=lower_bound(li+1,li+1+sz,p[i].y)-li;
add(u,v,1);
add(v,u,1);
du[u]++;du[v]++;
}
queueq;
for(int i=1;i<=sz;i++)
if(du[i]==1)q.push(i);
while(q.size())
{
int x=q.front();q.pop();
for(int i=head[x];i;i=ee[i].nxt)
{
int y=ee[i].to;
if(vs[y])continue;
du[y]--;
vs[x]=1;
if(du[y]==1)q.push(y);
}
}
int ans=0;
for(int i=1;i<=sz;i++)if(vs[i]||du[i]!=0)ans++;
printf("Case #%d: %d\n",CA,ans);
}
return 0;
}
K:
招待客人最大数量一定是b[1]。
然后进行贪心选择即可。
我为了省去思维量,直接用线段树维护了。。
#include
using namespace std;
typedef long long ll;
#define ls (o<<1)
#define rs (o<<1|1)
const int inf=1e9+7;
const int M = 1e5+7;
int mn[M<<2],tg[M<<2];
ll a[M],b[M];
void bd(int o,int l,int r)
{
tg[o]=0;
if(l==r)
{
mn[o]=b[l];
return ;
}
int m=(l+r)/2;
bd(ls,l,m);
bd(rs,m+1,r);
mn[o]=min(mn[ls],mn[rs]);
}
void pd(int o,int l,int r)
{
if(!tg[o])return ;
tg[ls]+=tg[o];
tg[rs]+=tg[o];
int m=(l+r)/2;
mn[ls]+=tg[o];
mn[rs]+=tg[o];
tg[o]=0;
}
void up(int o,int l,int r,int x,int y,int d)//区间加法
{
if(x<=l&&r<=y)
{
tg[o]+=d;mn[o]+=d;
return ;
}
pd(o,l,r);
int m=(l+r)/2;
if(x<=m)up(ls,l,m,x,y,d);
if(y>m)up(rs,m+1,r,x,y,d);
mn[o]=min(mn[ls],mn[rs]);
}
struct node{
int sm,mn,mx;
}tr[M];
int R,n;
void qu(int o,int l,int r)
{
// cout<'9')
{
if(ch=='-')
f=-1;
ch=getchar();
}
while(ch>='0'&&ch<='9')
{
x=x*10+ch-'0';
ch=getchar();
}
return x*f;
}
inline void write(__int128 x)
{
if(x<0)
{
putchar('-');
x=-x;
}
if(x>9)
write(x/10);
putchar(x%10+'0');
}
ll dp[M],id[M],sum[M];
int main()
{
int T;
cin>>T;
for(int CA=1;CA<=T;CA++)
{
scanf("%d",&n);
for(int i=1;i<=n;i++)scanf("%lld",&a[i]),sum[i]=sum[i-1]+a[i];
for(int i=1;i<=n;i++)scanf("%lld",&b[i]);
dp[1]=a[1],id[1]=1;
for(int i=2;i<=n;i++)
{
if(sum[i]>dp[i-1])dp[i]=sum[i],id[i]=i;
else dp[i]=dp[i-1],id[i]=id[i-1];
//cout<<"--- "<