7-20省选组(雅礼培训2018-1-2)
T1 串

- 无法取完的三种情况:
1,1,1,形如 aaaaaaaaaaaaaaaaaaaaaaaa
2,2,2,形如 aaabaaaaaabaaaaaabaaa
3,3,3,形如 abababaabababaabababa - 若不是回文串输出111
- 若是回文串输出222
- 为什么不可能操作三次或以上:
反证法。假设需要操作至少三次,则必有至少两个回文前缀,它们的对称轴位置不一样,利用这两个对称轴可以使很多位置的字符相等,最后只能出现以上无法取完的三种情况,矛盾。
#include<bits/stdc++.h>
#define FOR(i,a,b) for (register int i=a;i<=b;i++)
#define For(i,a,b) for (register int i=a;i>=b;i--)
#define mem(i,j) memset(i,j,sizeof(i))
#define GO(u) for (register int j=f[u];j!=-1;j=nxt[j])
using namespace std;
typedef long long ll;
const int N=2e5+5;
int T,n,check,ans[N];
char s[N];
int read()
{
int x=0,f=1;
char c=getchar();
while (c<'0'||c>'9') {if (c=='-') f=-1;c=getchar();}
while (c>='0'&&c<='9') {x=(x<<1)+(x<<3)+c-'0';c=getchar();}
return f*x;
}
int HW(int l,int r)
{
FOR(i,l,(l+r)>>1)
if (s[i]!=s[r+l-i]) return 0;
return 1;
}
int No()
{
int hw=HW(1,n);
int c1=1,c2=0,c3=0,tmp=0;
FOR(i,2,n) if (s[i]!=s[1]) c1=0;
if (hw)
{
c3=1;
FOR(i,1,n) if (s[i]==s[1]) tmp++;
if (tmp==n-1&&n%2==1&&s[(n+1)/2]!=s[1]) c2=1;
FOR(i,1,n)
{
if (i%2==1&&s[i]!=s[1]) c3=0;
if (i%2==0&&s[i]!=s[2]) c3=0;
}
}
return c1||c2||c3;
}
void Solve()
{
if (No()) ans[++ans[0]]=-1;
else if (HW(1,n)) ans[++ans[0]]=2;
else ans[++ans[0]]=1;
return;
}
int main()
{
// freopen("testdata.in","r",stdin);
T=read();
while (T--)
{
n=read();
scanf("%s",s+1);
Solve();
}
FOR(i,1,ans[0]) printf("%d\n",ans[i]);
return 0;
}
T2 变量

最小割建模
- 对于每一个变量w[i]w[i]w[i],连向源点流量−W-W−W,连向汇点流量WWW(负的流量加上一个正数最后减回来)
- 对于不带绝对值的贡献直接加在第一种上面
- 对于带绝对值的贡献,若两变量相等则无贡献,不相等则两倍贡献,所以将两个变量连上流量为两倍贡献的双向边
- 对于最后三种限制,随便连几个infinfinf的边限制一下
- 发现WWW可以提出来,那就少开几个longlonglong longlonglong最后乘上WWW
#include<bits/stdc++.h>
#define FOR(i,a,b) for (register int i=a;i<=b;i++)
#define For(i,a,b) for (register int i=a;i>=b;i--)
#define mem(i,j) memset(i,j,sizeof(i))
#define GO(u) for (register int j=first[u];j!=-1;j=nxt[j])
using namespace std;
typedef long long ll;
const int N=2e5+5;
const ll inf=1e18;
int t,n,W,p,q,x,y,z,ai,bi,ci,di,ei,fi,r,mx;
int val[N],v[1010][1010];
int tot=1,first[N],nxt[N<<1];
int S,T,mincut,flow,depth[N];
ll ans[N];
queue <int> Q;
struct E
{
int u,v;
ll flow;
}e[N<<1];
inline void Add(int u,int v,ll flow)
{
tot++;
nxt[tot]=first[u];
first[u]=tot;
e[tot]=(E){u,v,flow};
return;
}
inline void Addedge(int u,int v,ll flow)
{
Add(u,v,flow);
Add(v,u,0);
return;
}
inline int read()
{
int x=0,f=1;
char c=getchar();
while (c<'0'||c>'9') {if (c=='-') f=-1;c=getchar();}
while (c>='0'&&c<='9') {x=(x<<1)+(x<<3)+c-'0';c=getchar();}
return f*x;
}
inline void Init()
{
mincut=0;
mx=-1;
tot=1;
mem(first,-1);
mem(val,0);
mem(v,0);
FOR(i,1,n) val[i]=1;
return;
}
inline int BFS()
{
while (Q.size()) Q.pop();
mem(depth,0);
depth[S]=1;
Q.push(S);
while (Q.size())
{
int tmp=Q.front();
Q.pop();
GO(tmp)
{
int v=e[j].v;
if (!e[j].flow) continue;
if (depth[v]) continue;
depth[v]=depth[tmp]+1;
Q.push(v);
}
}
if (depth[T]) return 1;
else return 0;
}
inline ll Dinic(int u,ll f)
{
if (u==T) return f;
ll rest=f,k;
GO(u)
{
int v=e[j].v;
if (!e[j].flow) continue;
if (depth[v]!=depth[u]+1) continue;
k=Dinic(v,min(rest,e[j].flow));
if (!k) continue;
e[j].flow-=k;
e[j^1].flow+=k;
rest-=k;
}
return f-rest;
}
inline void Check_line()
{
for (int i=2;i<=tot;i+=2) printf("%d %d %lld\n",e[i].u,e[i].v,e[i].flow);
return;
}
ll bz[N];
inline void Check_Ans()
{
FOR(i,1,ans[0]) bz[i]=read();
FOR(i,1,ans[0]) printf("%lld %lld %d\n",ans[i],bz[i],(ans[i]==bz[i]));
return;
}
int main()
{
// freopen("variable1.in","r",stdin);
// freopen("myans.out","w",stdout);
t=read();
while (t--)
{
n=read(),W=read(),p=read(),q=read();
Init();
S=n+1,T=n+2;
FOR(i,1,p)
{
x=read(),y=read(),z=read(),ai=read(),bi=read(),ci=read(),di=read(),ei=read(),fi=read();
val[x]+=di-fi;
val[y]+=ei-di;
val[z]+=fi-ei;
v[min(x,y)][max(x,y)]+=2*ai;
v[min(y,z)][max(y,z)]+=2*bi;
v[min(x,z)][max(z,x)]+=2*ci;
}
FOR(i,1,n) mx=max(mx,val[i]);
mx++;
FOR(i,1,n)
{
Addedge(S,i,mx-val[i]);
Addedge(i,T,mx+val[i]);
}
FOR(i,1,n-1)
FOR(j,i+1,n) if (v[i][j]) Addedge(i,j,v[i][j]),Addedge(j,i,v[i][j]);
FOR(i,1,q)
{
x=read(),y=read(),r=read();
switch (r)
{
case 0:
Addedge(x,y,inf);
break;
case 1:
Addedge(x,y,inf);
Addedge(y,x,inf);
break;
case 2:
Addedge(x,T,inf);
Addedge(S,y,inf);
break;
}
}
// Check_line();
while (BFS())
if ((flow=Dinic(S,inf))) mincut+=flow;
ans[++ans[0]]=(1LL*mincut-n*mx)*W;
}
// Check_Ans();
FOR(i,1,ans[0]) printf("%lld\n",ans[i]);
return 0;
}
T3 取石子

每堆石子对于(a+b)(a+b)(a+b)取模
假设a<ba < ba<b
然后分以下四种情况讨论
- case1:case 1:case1: x<a<bx<a<bx<a<b 两个人都不能取,这堆石头没有实际作用,计数的时候统计上即可
- case2:case 2:case2: a≤x<ba \leq x<ba≤x<b 只有A能取,这种石头只要存在则A必胜
- case3:case 3:case3: b≤x<2∗ab \leq x<2*ab≤x<2∗a 两个人都能取,并且只能取一次,胜负和奇偶有关
- case4:case 4:case4: b≤xb \leq xb≤x ,2∗a≤x2*a \leq x2∗a≤x 两个人都能取,但是B只能取一次,A可以取多次
结论如下:
- 存在 case2case 2case2 则A必胜
- 存在两个或以上 case4case 4case4 则A必胜
- 存在一个 case4case 4case4 和奇数个 case3case 3case3 ,先手必胜
- 存在一个 case4case 4case4 和偶数个 case3case 3case3, A必胜
- 存在奇数/偶数个 case3case 3case3,先手/后手必胜
#include<bits/stdc++.h>
#define FOR(i,a,b) for (register int i=a;i<=b;i++)
using namespace std;
typedef long long ll;
const int N=2e5+5;
const int mod=1e9+7;
ll n,a,b,x[N],cnt1=0,cnt2=0,cnt3=0,cnt4=0,mn,mx,ans1=0,ans2=0,ans3=0,ans4=0;
ll read()
{
ll x=0,f=1;
char c=getchar();
while (c<'0'||c>'9') {if (c=='-') f=-1;c=getchar();}
while (c>='0'&&c<='9') {x=(x<<1)+(x<<3)+c-'0';c=getchar();}
return f*x;
}
ll qpow(ll A,ll B)
{
ll ret=1;
while (B)
{
if (B&1) ret=ret*A%mod;
B>>=1;
A=A*A%mod;
}
return ret;
}
void Solve()
{
ans1=(ans1+(qpow(2,cnt2)-1)*qpow(2,n-cnt2)%mod)%mod;//存在case 2
if (cnt4>=2) ans1=(ans1+(qpow(2,cnt4)-1-cnt4)*qpow(2,cnt1+cnt3)%mod)%mod;//两个 case 4
if (cnt4)// 一个case 4
{
//讨论case 3奇偶
if (cnt3) ans1=(ans1+qpow(2,cnt1+cnt3-1)*cnt4%mod)%mod,ans3=(ans3+qpow(2,cnt1+cnt3-1)*cnt4%mod)%mod;//case 3大于等于1是奇偶对半分,必定是偶数(qpow(2,cnt3))
else ans3=(ans3+qpow(2,cnt1)*cnt4%mod)%mod;
}
if (cnt3) ans3=(ans3+qpow(2,cnt3+cnt1-1)%mod)%mod,ans4=(ans4+qpow(2,cnt3+cnt1-1)%mod)%mod;//没有cacse 4,讨论case 3奇偶
else if (cnt1) ans4=(ans4+qpow(2,cnt1))%mod;
return;
}
int main()
{
n=read(),a=read(),b=read();
FOR(i,1,n) x[i]=read()%(a+b);
mn=min(a,b);
mx=max(a,b);
FOR(i,1,n)
{
if (x[i]<mn) cnt1++;
if (mn<=x[i]&&x[i]<mx) cnt2++;
if (x[i]>=mx&&x[i]<2*mn) cnt3++;
if (x[i]>=mx&&x[i]>=2*mn) cnt4++;
}
Solve();
if (a>b) swap(ans1,ans2);
printf("%lld %lld %lld %lld\n",ans1,ans2,ans3,ans4);
return 0;
}
867

被折叠的 条评论
为什么被折叠?



