传送门:然而并没有...
这两天测试状态比较奇怪,前面1.5h-2h完全不知所措,一脸茫然,感觉自己吃枣药丸
后面才发现有很多题可捉的,并没有想象的那么难,但是时间已经不充裕了...
R2D2
T1:不知所措数学题
一开始总想着有什么DP可以拿一些部分分
然而连30分DP都不会....
咦,好像有大样例
那就找一发规律
妈呀真是2^(nk)
快速幂完事....
考完冷静了一下发现还是比较容易证的
首先n位每位相互独立,所以可以只考虑一位
设f[k]表示k*k的三角形的方案数
考虑f[k+1]怎么递推
如果最左下角的数是0,那么最后一行已经确定了,都会是0
而且不会对上面的k*k的三角形有影响,所以方案数是f[k]
如果是1,同理,最左边一行已经确定了,都必须是1
而且也不会对右边的k*k的三角形有影响,所以方案数是f[k]
所以f[k+1]=2*f[k]
所以一位的答案就是2^k
n位乘起来就好了,答案就是2^(nk)
T2:数据结构题?
一看到这题我就觉得是数据结构题,然而想来想去并不知道怎么维护....于是弃疗了
后来我才发现一个显然的性质
就是最大和最小一定取在端点,不然不是最优
然后我们就可以分数规划了
情况有点多
假设i是右端点,j是左端点
假设a[i]为max,a[j]为min
那么(a[i]-a[j])/(i-j+K)=ans
变形得(a[i]-i*ans)-(a[j]-j*ans)=k*ans
所以我们二分一下ans,有满足左边大于右边的,ans就可以更大
左边最大值可以用单调队列做
记A[i]=a[i]-ans*i
如果后面加进来的A[i]比队尾要小,队尾就没有意义了,可以删去
对于区间长度是[L,R]的限制,初始时保持距离为L,加入队列时从队头删去距离超过R-1的点即可
反过来类似,注意一些细节
另外就是区间长为L时
类似地,(a[i]-a[j])/(L-1+K)=ans
变形得:a[i]-a[j]=ans*(L-1+K)
也是二分,单调队列维护即可
复杂度O(nlogmaxans)
T3:字符串神题?
突然发现字符串长<=10.....
拿个可持久化trie维护一下就好了
儿子节点从父亲节点继承trie,再把边上的字符串插入进去即可
每次用ans[x]+ans[y]-2*ans[lca]即可
R3D1
T1:一开始想到了一个玄学做法,好像很复杂的样子...然后就安心打暴力去了
后来证了一下发现是对了,加个bitset好像可以卡过
我们对于每个点求出它能到哪些点,记为g[i][maxn],这个可以压位做到m*n/32
然后对于每个点v,处理哪些连向它的边可删
如果一个它的前驱x能够到它的另一个前驱y
那么显然x连向它的边可以删去了
然后证明没有其他可删的边
假设有一个边可删,且不满足上面的条件
那么说明x到v有其他路径
那么这条路经一定要经过v的另一个前驱z,那么x可以到z,不符假设
所以不存在这样的边
具体实现就对每个点求一个bitset,表示是否是x的前驱
在把它和每个前驱的g[i]and一下,如果有1,就说明可以从其他点过来,然后就可以删掉这条边
然后发现有点卡常,怕70分都没了,于是只开到1000,70保平安...
然后发现标程压64位.....
T2:神奇的插头DP
妈呀200*200....
一定有特殊的DP方法
D了半天不知所措....
突然发现这是很简单的网络流,每栋房子是一个点,源向它连卖给A的权值,它向汇连卖给B的的权值,相邻的点连建围墙的权值,求出最小割,拿总收益减去就是了...
然后就是15分钟写网络流系列...
然后就爆零被教做人了...
T3:这个真是字符串神题,看了标程好像是后缀数组,暴力还挂了,不知所措...
得分情况:100+0+100+70+0+0
有些题目就是要敢于去想,要相信能写出来
但是有时写暴力求稳也是很重要的...
R2D1
T1:
<span style="font-size:14px;">#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
typedef long long ll;
const ll mod=(ll)1e9+7;
using namespace std;
int n,k;
ll qpow(int a,ll b){
ll res=1,j=a;
while (b){
if (b&1) res=res*j%mod;
j=j*j%mod,b>>=1;
}
return res;
}
int main(){
scanf("%d%d",&n,&k);
printf("%lld\n",qpow(2,1ll*n*k));
return 0;
}</span>
T2:
<span style="font-size:14px;">#include<cstdio>
#include<cstring>
#include<cassert>
#include<iostream>
#include<algorithm>
const double eps=1e-6;
const int maxn=100010;
using namespace std;
int cas,a[maxn],n,K,L,R;
struct Tque{
int pos[maxn],head,tail;double val[maxn];
void clear(){head=1,tail=0;}
void pushmin(int p,double v){
//maximize a[i]-miu*i-a[j]+miu*j
//if A[j]<=A[q[tail]]
//because j>q[tail]
//j is better than q[tail]
while (head<=tail&&v<=val[tail]) tail--;
val[++tail]=v,pos[tail]=p;
}
void pushmax(int p,double v){
while (head<=tail&&v>=val[tail]) tail--;
val[++tail]=v,pos[tail]=p;
}
void pop1(int p){while (head<=tail&&p-pos[head]+1>R) ++head;assert(p-pos[head]+1<=R);}
void pop2(int p){while (head<=tail&&pos[head]<p-L+1) ++head;assert(pos[head]>=p-L+1);}
double top(){return val[head];}
}q;
bool check(double miu){
q.clear();
for (int i=L;i<=n;i++){
int j=i-L+1;
q.pushmin(j,a[j]-j*miu),q.pop1(i);
if (a[i]-miu*i-q.top()+eps>=K*miu) return 1;
}
q.clear();
for (int i=L;i<=n;i++){
int j=i-L+1;
q.pushmax(j,a[j]+j*miu),q.pop1(i);
if (q.top()-a[i]-miu*i+eps>=K*miu) return 1;
}
q.clear();
for (int i=1;i<=n;i++){
q.pushmin(i,a[i]),q.pop2(i);
if (a[i]-q.top()+eps>=(L-1+K)*miu) return 1;
}
q.clear();
for (int i=1;i<=n;i++){
q.pushmax(i,a[i]),q.pop2(i);
if (q.top()-a[i]+eps>=(L-1+K)*miu) return 1;
}
return 0;
}
int main(){
//freopen("gift.in","r",stdin);freopen("gift.out","w",stdout);
scanf("%d",&cas);
while (cas--){
scanf("%d%d%d%d",&n,&K,&L,&R);
for (int i=1;i<=n;i++) scanf("%d",&a[i]);
double l=0.0,r=1000.0,mid=500.0;
while (r-l>eps){
if (check(mid)) l=mid;
else r=mid;
mid=(l+r)/2;
}
printf("%.4lf\n",l);
}
return 0;
}
/*
1
5 1 2 4
1 2 3 4 5
*/
</span>
T3:
<span style="font-size:14px;">#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
const int maxn=100010,maxm=200010,maxt=1200010;
using namespace std;
int n,Q,pre[maxm],now[maxn],son[maxm],val[maxm][15],tot,pp[15],fa[maxn][22],dep[maxn];char tmp[15];
struct Trie{
int root[maxn],ch[maxt][28],tot,cnt[maxt];
void insert(int now,int pre,int s[]){
int len=0;
while (s[len+1]) len++;
//for (int i=1;i<=len;i++) printf("%d ",s[i]);puts("s[i]");
for (int i=1;i<=len;i++){
for (int j=1;j<=26;j++){
if (j==s[i]) ch[now][j]=++tot,cnt[tot]=cnt[ch[pre][j]]+1;
else ch[now][j]=ch[pre][j];
}
now=ch[now][s[i]],pre=ch[pre][s[i]];
}
for (int j=1;j<=26;j++) ch[now][j]=ch[pre][j];
}
int query(int now,int s[]){
for (int i=1;s[i];i++) now=ch[now][s[i]];//,printf("now=%d s[i]=%d cnt=%d\n",now,s[i],cnt[now])
//puts("\n");
return cnt[now];
}
}T;
void add(int a,int b){
pre[++tot]=now[a],now[a]=tot,son[tot]=b;
for (int i=1;pp[i];i++) val[tot][i]=pp[i];
}
void dfs(int x){
for (int i=1;i<=19;i++) fa[x][i]=fa[fa[x][i-1]][i-1];
for (int y=now[x];y;y=pre[y]) if (son[y]!=fa[x][0]){
T.root[son[y]]=++T.tot,T.insert(T.root[son[y]],T.root[x],val[y]);
dep[son[y]]=dep[x]+1,fa[son[y]][0]=x,dfs(son[y]);
}
}
int lca(int a,int b){
if (dep[a]<dep[b]) swap(a,b);
for (int h=dep[a]-dep[b],i=18;h;i--) if (h&(1<<i)) h-=(1<<i),a=fa[a][i];
if (a==b) return a;
for (int i=18;i>=0;i--)
if (fa[a][i]!=fa[b][i]) a=fa[a][i],b=fa[b][i];
return fa[a][0];
}
void change(){
int len=strlen(tmp+1);
memset(pp,0,sizeof(pp));
for (int i=1;i<=len;i++) pp[i]=tmp[i]-'a'+1;
}
int main(){
freopen("strings.in","r",stdin);freopen("strings.out","w",stdout);
scanf("%d",&n);
for (int i=1,x,y;i<n;i++){
scanf("%d%d%s",&x,&y,tmp+1);
change(),add(x,y),add(y,x);
}
T.root[1]=++T.tot,dfs(1);
scanf("%d",&Q);
for (int i=1,x,y;i<=Q;i++){
scanf("%d%d%s",&x,&y,tmp+1);
int u=lca(x,y);change();
//printf("x=%d y=%d lca=%d\n",x,y,u);
printf("%d\n",T.query(T.root[x],pp)+T.query(T.root[y],pp)-2*T.query(T.root[u],pp));
/*printf("x=%d\n",T.query(T.root[x],pp));
printf("y=%d\n",T.query(T.root[y],pp));
printf("lca=%d\n",T.query(T.root[u],pp));*/
}
return 0;
}</span>
R3D1
T1:这个程序只能过70分,但是是标算,还要特殊的卡常数技巧(标程是压64位,可能在64位机上要快一些就过了)
#include<cstdio>
#include<bitset>
#include<cstring>
#include<iostream>
#include<algorithm>
const int maxn1=18,maxn=30010,maxm=100010;
using namespace std;
struct Edge{int x,y;}E[maxm];
bitset<maxn> map[maxn];
int n,m,ans,pw[maxn1],ord[maxn];bool g[maxn1][maxn1],con[maxn1][maxn1],tmp[maxn1][maxn1],bo[maxn1];
struct Twork1{
void dfs(int x){
bo[x]=1;
for (int i=1;i<=n;i++) if (g[x][i]&&!bo[i]) dfs(i);
}
bool check(int s){
memset(g,0,sizeof(g)),memset(tmp,0,sizeof(tmp));
for (int i=0;i<m;i++) if (pw[i]&s) g[E[i].x][E[i].y]=1;
for (int i=1;i<=n;i++){
memset(bo,0,sizeof(bo)),dfs(i);
for (int j=1;j<=n;j++) if (bo[j]) tmp[i][j]=1;
}
for (int i=1;i<=n;i++)
for (int j=1;j<=n;j++) if (tmp[i][j]!=con[i][j]) return 0;
return 1;
}
void work(){
for (int i=0;i<m;i++) scanf("%d%d",&E[i].x,&E[i].y),g[E[i].x][E[i].y]=1;
for (int i=1;i<=n;i++){
memset(bo,0,sizeof(bo)),dfs(i);
for (int j=1;j<=n;j++) if (bo[j]) con[i][j]=1;
}
for (int s=0;s<pw[m];s++){
int cnt=0;
for (int i=0;i<m;i++) if (s&pw[i]) cnt++;
cnt=m-cnt;
//printf("%d %d\n",s,cnt);
if (check(s)) ans=max(cnt,ans);
}
printf("%d\n",ans);
}
}T1;
struct Twork2{
int pre[maxm],now[maxn],son[maxm],tot,in[maxn],q[maxn],head,tail;
void add(int a,int b){pre[++tot]=now[a],now[a]=tot,son[tot]=b,in[b]++;}
void top1(){
head=0,tail=0;
for (int i=1;i<=n;i++) map[i][i]=1;
for (int i=1;i<=n;i++) if (!in[i]) q[++tail]=i;
while (head!=tail){
int x=q[++head];
for (int y=now[x];y;y=pre[y]){
if (!(--in[son[y]])) q[++tail]=son[y];
map[son[y]]|=map[x];
}
}
for (int i=1;i<=n;i++) map[i][i]=0;
}
void work(){
for (int i=1,x,y;i<=m;i++) scanf("%d%d",&x,&y),add(y,x);
top1();
bitset<maxn> tmp;
int ans=0;
for (int x=1;x<=n;x++){
tmp.reset();
for (int y=now[x];y;y=pre[y])
tmp[son[y]]=1;
for (int y=now[x];y;y=pre[y])
if ((tmp&map[son[y]]).any()) ans++;
}
printf("%d\n",ans);
}
}T2;
int main(){
freopen("graph.in","r",stdin);freopen("graph.out","w",stdout);
pw[0]=1;for (int i=1;i<=16;i++) pw[i]=pw[i-1]<<1;
scanf("%d%d",&n,&m);
if (n<=15&&m<=15) T1.work();
else T2.work();
return 0;
}
/*
5 6
1 2
2 3
3 5
4 5
1 5
1 3
7 8
1 2
2 5
5 7
1 3
6 7
1 4
4 7
3 5
*/
T2:
#include<cstdio>
#include<cassert>
#include<cstring>
#include<iostream>
#include<algorithm>
#define aabs(a) (a>0?a:-(a))
const int maxn=500010,maxm=1000010,inf=(int)1e9;
using namespace std;
int n,m,ans,pre[maxm],now[maxn],son[maxm],val[maxm],tot,dis[maxn],head,tail,q[maxm+10];
int id(int x,int y){return (x-1)*m+y;}
struct Flow{
int S,T;
void add(int a,int b,int c){pre[++tot]=now[a],now[a]=tot,son[tot]=b,val[tot]=c;}
void ins(int a,int b,int c){add(a,b,c),add(b,a,0);assert(tot<maxn);}
void clear(){memset(now,0,sizeof(now)),tot=1,S=0,T=maxn-1;}
bool bfs(){
memset(dis,-1,sizeof(dis));
q[tail=1]=S,dis[S]=head=0;
while (head!=tail){
if (++head>maxn) head=1;
int x=q[head];
for (int y=now[x];y;y=pre[y])
if (val[y]&&dis[son[y]]==-1){
if (++tail>maxn) tail=1;
dis[son[y]]=dis[x]+1,q[tail]=son[y];
}
}
return dis[T]>0;
}
int find(int x,int low){
if (x==T) return low;
int y,res=0;
for (y=now[x];y;y=pre[y]){
if (dis[son[y]]!=dis[x]+1||!val[y]) continue;
int tmp=find(son[y],min(low,val[y]));
res+=tmp,low-=tmp,val[y]-=tmp,val[y^1]+=tmp;
if (!low) break;
}
if (!y) dis[x]=-1;
return res;
}
void work(){
int res=0;
while (bfs()) res+=find(S,inf);
printf("%d\n",ans-res);
}
}F;
void init(){
scanf("%d%d",&n,&m),F.clear();
for (int i=1;i<=n;i++)
for (int j=1,v;j<=m;j++){
scanf("%d",&v),ans+=aabs(v);
if (v>=0) F.ins(F.S,id(i,j),v);
else F.ins(id(i,j),F.T,-v);
}
for (int i=1;i<n;i++)
for (int j=1,v;j<=m;j++)
scanf("%d",&v),F.ins(id(i,j),id(i+1,j),v),F.ins(id(i+1,j),id(i,j),v);
for (int i=1;i<=n;i++)
for (int j=1,v;j<m;j++)
scanf("%d",&v),F.ins(id(i,j),id(i,j+1),v),F.ins(id(i,j+1),id(i,j),v);
}
int main(){
init(),F.work();
return 0;
}
/*
5 5
-3 7 0 0 0
8 0 7 -10 0
0 7 0 1 0
0 0 0 0 0
-8 0 0 2 10
4 50 50 1 50
50 50 1 9 50
50 50 1 1 50
2 50 50 50 50
2 50 50 50
50 50 1 1
50 1 8 1
50 50 50 50
1 50 50 50
*/
T3:不知所措....