7-20省选组(雅礼培训2018-1-2)
T1 串
- 无法取完的三种情况:
1 , 1, 1,形如 a a a a a a a a aaaaaaaa aaaaaaaa
2 , 2, 2,形如 a a a b a a a aaabaaa aaabaaa
3 , 3, 3,形如 a b a b a b a abababa abababa - 若不是回文串输出 1 1 1
- 若是回文串输出 2 2 2
- 为什么不可能操作三次或以上:
反证法。假设需要操作至少三次,则必有至少两个回文前缀,它们的对称轴位置不一样,利用这两个对称轴可以使很多位置的字符相等,最后只能出现以上无法取完的三种情况,矛盾。
#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,连向汇点流量 W W W(负的流量加上一个正数最后减回来)
- 对于不带绝对值的贡献直接加在第一种上面
- 对于带绝对值的贡献,若两变量相等则无贡献,不相等则两倍贡献,所以将两个变量连上流量为两倍贡献的双向边
- 对于最后三种限制,随便连几个 i n f inf inf的边限制一下
- 发现 W W W可以提出来,那就少开几个 l o n g l o n g long long longlong最后乘上 W W W
#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
<
b
a < b
a<b
然后分以下四种情况讨论
- c a s e 1 : case 1: case1: x < a < b x<a<b x<a<b 两个人都不能取,这堆石头没有实际作用,计数的时候统计上即可
- c a s e 2 : case 2: case2: a ≤ x < b a \leq x<b a≤x<b 只有A能取,这种石头只要存在则A必胜
- c a s e 3 : case 3: case3: b ≤ x < 2 ∗ a b \leq x<2*a b≤x<2∗a 两个人都能取,并且只能取一次,胜负和奇偶有关
- c a s e 4 : case 4: case4: b ≤ x b \leq x b≤x , 2 ∗ a ≤ x 2*a \leq x 2∗a≤x 两个人都能取,但是B只能取一次,A可以取多次
结论如下:
- 存在 c a s e 2 case 2 case2 则A必胜
- 存在两个或以上 c a s e 4 case 4 case4 则A必胜
- 存在一个 c a s e 4 case 4 case4 和奇数个 c a s e 3 case 3 case3 ,先手必胜
- 存在一个 c a s e 4 case 4 case4 和偶数个 c a s e 3 case 3 case3, A必胜
- 存在奇数/偶数个 c a s e 3 case 3 case3,先手/后手必胜
#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;
}