noip模拟64[开题失误]
noip模拟64 solutions
这个吧,AaMuXiiiiii太强了,把第一题切了,我非常生气,然后给了他一巴掌
然后几秒种后我也切了(注意不是考场上)
不过我竟然对最后一题有感觉,不知道是做题策略的问题,还是我脑子抽抽了
所以以后还是好好看题,好好的决定开题顺序。。。
T1 三元组
这个我也是枚举\(b^2\)的位置,但是我是\(n^2\)的,直接枚举的好吧
但是我也想仔细观察观察但是没观察出来
a的值域是连续的
这样的话我们只需要找到\(a\)的值域的左右端点,直接在\(c^3\)的树状数组上查就好了
AC_code
#include<bits/stdc++.h>
using namespace std;
#define oj
#define int long long
#define fo(i,x,y) for(int i=(x);i<=(y);i++)
#define fu(i,x,y) for(int i=(x);i>=(y);i--)
const int N=1e5+5;
int T,n,m,ans;
struct BIT{
int tr[N];
void ins(int x,int v){
if(x==0)return tr[0]+=v,void();
for(int i=x;i<m;i+=(i&(-i)))tr[i]+=v;
}
int query(int x){
if(x<0)return 0;
int ret=tr[0];
for(int i=x;i>0;i-=(i&(-i)))ret+=tr[i];
return ret;
}
}bit;
signed main(){
#ifdef oj
freopen("exclaim.in","r",stdin);
freopen("exclaim.out","w",stdout);
#endif
scanf("%lld",&T);
fo(t,1,T){
ans=0;
scanf("%lld%lld",&n,&m);
fo(i,1,n)bit.ins(i*i*i%m,1);
fo(i,1,n){
int now=i*i%m;
int l=(1+i*i)%m,r=(i+i*i)%m;
if(i%m==0)ans+=bit.query(m-1)*(i/m);
else if(l<=r)ans+=bit.query(r)-bit.query(l-1)+bit.query(m-1)*(i/m);
else ans+=(bit.query(m-1)-bit.query(l-1))+bit.query(r)+bit.query(m-1)*(i/m);
bit.ins(i*i*i%m,-1);
}
printf("Case %lld: %lld\n",t,ans);
}
}
T2 简单的字符串
这个别找我,我是暴力艹过去的
直接\(n^3\)开干,用两个\(hash\),一个用来判断字符集是否相等
这个实现的话,就直接在对应的字母的那一位\(+1\)就好了
另一个用来判断字符串是否相等就好了
AC_code
#include<bits/stdc++.h>
using namespace std;
#define oj
#define ull unsigned long long
#define fo(i,x,y) for(int i=(x);i<=(y);i++)
#define fu(i,x,y) for(int i=(x);i>=(y);i--)
const int N=5005;
const ull bas=13331;
int n,a[N],ji[N],ans;
ull ba[N],hs[N],gs[N];
ull ksm(ull x,int y){
ull ret=1;
while(y){
if(y&1)ret=ret*x;
x=x*x;y>>=1;
}return ret;
}
signed main(){
#ifdef oj
freopen("s.in","r",stdin);
freopen("s.out","w",stdout);
#endif
scanf("%d",&n);
fo(i,1,n)scanf("%d",&a[i]);
ba[0]=1;fo(i,1,n)ba[i]=ba[i-1]*bas;
fo(i,1,n)hs[i]=hs[i-1]*bas+a[i];
fo(i,1,n)gs[i]=gs[i-1]+ksm(bas,a[i]);
for(int l=2;l<=n;l+=2){
fo(i,1,n-l+1){
int j=i+l-1,len=l>>1;
if(gs[j]-gs[i+len-1]!=gs[i+len-1]-gs[i-1])continue;
bool flag=false;
fo(k,0,len-1)if(hs[i+k]-hs[i-1]*ba[k+1]==hs[j]-hs[j-k-1]*ba[k+1]&&hs[i+len-1]-hs[i+k]*ba[len-1-k]==hs[j-k-1]-hs[i+len-1]*ba[len-1-k]){flag=true;break;}
if(flag)ans++;
}
}
printf("%d",ans);
}
正解戳这里
T3 环路
这个确实一眼就能看出来是矩阵乘法,但是我只会最最最基础的
就是直接一遍一遍的乘,然后每一次都把主对角线的全都加起来
AC_code
#include<bits/stdc++.h>
using namespace std;
#define oj
#define int long long
#define fo(i,x,y) for(int i=(x);i<=(y);i++)
#define fu(i,x,y) for(int i=(x);i>=(y);i--)
const int N=105;
int n,m,mod,ans;
char s[N];
struct matrix{
int x[N][N];
matrix(){memset(x,0,sizeof(x));}
matrix operator * (matrix a)const{
matrix ret;
fo(i,1,n)fo(j,1,n)fo(k,1,n)ret.x[i][j]=(ret.x[i][j]+x[i][k]*a.x[k][j])%mod;
return ret;
}
}xs;
signed main(){
#ifdef oj
freopen("tour.in","r",stdin);
freopen("tour.out","w",stdout);
#endif
scanf("%lld",&n);
fo(i,1,n){
scanf("%s",s+1);
fo(j,1,n)if(s[j]=='Y')xs.x[i][j]=1;
}
scanf("%lld%lld",&m,&mod);
matrix res;m--;
fo(i,1,n)res.x[i][i]=1;
fo(t,1,m){
res=res*xs;
fo(i,1,n)ans=(ans+res.x[i][i])%mod;
}
printf("%lld",ans);
}
另外一个就比较高级了,可以给\(i\)和\(i+n\)连边再给\(i+n\)和\(i+n\)连边
这样你每次统计的答案就全部放到\(i+n\)上去了
然后就可以直接快速幂了
AC_code
#include<bits/stdc++.h>
using namespace std;
#define oj
#define int long long
#define fo(i,x,y) for(int i=(x);i<=(y);i++)
#define fu(i,x,y) for(int i=(x);i>=(y);i--)
const int N=205;
int n,m,mod,ans;
char s[N];
struct matrix{
int x[N][N];
matrix(){memset(x,0,sizeof(x));}
matrix operator * (matrix a)const{
matrix ret;
fo(i,1,2*n)fo(j,1,2*n)fo(k,1,2*n)ret.x[i][j]=(ret.x[i][j]+x[i][k]*a.x[k][j])%mod;
return ret;
}
}xs;
signed main(){
#ifdef oj
freopen("tour.in","r",stdin);
freopen("tour.out","w",stdout);
#endif
scanf("%lld",&n);
fo(i,1,n){
scanf("%s",s+1);
fo(j,1,n)if(s[j]=='Y')xs.x[i][j]=1;
xs.x[i][n+i]=1;xs.x[n+i][n+i]=1;
}
scanf("%lld%lld",&m,&mod);
matrix res;
fo(i,1,2*n)res.x[i][i]=1;
while(m){
if(m&1)res=res*xs;
xs=xs*xs;m>>=1;
}
fo(i,1,n)ans=(ans+res.x[i][n+i])%mod;
printf("%lld",ans-n);
}
最后一个正解就是分治的算法,因为后面的矩阵可以直接由前面的举证相乘得到
所以这样就可以直接优化到\(log\)
AC_code
#include<bits/stdc++.h>
using namespace std;
#define oj
#define int long long
#define fo(i,x,y) for(int i=(x);i<=(y);i++)
#define fu(i,x,y) for(int i=(x);i>=(y);i--)
const int N=105;
int n,m,mod,ans;
char s[N];
struct matrix{
int x[N][N];
matrix(){memset(x,0,sizeof(x));}
matrix operator * (matrix a)const{
matrix ret;
fo(i,1,n)fo(j,1,n)fo(k,1,n)ret.x[i][j]=(ret.x[i][j]+x[i][k]*a.x[k][j])%mod;
return ret;
}
matrix operator + (matrix a)const{
matrix ret;
fo(i,1,n)fo(j,1,n)ret.x[i][j]=(x[i][j]+a.x[i][j])%mod;
return ret;
}
}xs,ys;
void print(matrix a){
fo(i,1,n){fo(j,1,n)cout<<a.x[i][j]<<" ";cout<<endl;}
cout<<endl;
}
matrix sol(int l,int r){
if(l==r)return xs;
int mid=l+r-1>>1;
matrix le=sol(l,mid);
if(l+mid+mid==r){
matrix ri=le*ys;
ys=ys*ys*xs;
matrix ret=le+ri+ys;
return ret;
}
else {
matrix ri=le*ys;
ys=ys*ys;
matrix ret=le+ri;
return ret;
}
}
signed main(){
#ifdef oj
freopen("tour.in","r",stdin);
freopen("tour.out","w",stdout);
#endif
scanf("%lld",&n);
fo(i,1,n){
scanf("%s",s+1);
fo(j,1,n)if(s[j]=='Y')xs.x[i][j]=1;
}ys=xs;
scanf("%lld%lld",&m,&mod);m--;
matrix res=sol(1,m);
fo(i,1,n)ans=(ans+res.x[i][i])%mod;
printf("%lld",ans);
}
T4 过河
这个首先需要一个神猪,这个存在于所有的打架关系
我们必须找到这样一个神猪,这样才可以吧他们都运过去
第一步我们就把神猪运过去,
然后慢慢的把剩下的猪运过去,注意要保证这些猪不能构成打架关系
但是这一次运的最后一只是可以的,因为你人去看这这些猪了
然后下一步就是将神猪运回来,再把剩下的运过去,这时候第一次运的猪可以和其他的有交集
但是剩下的就不行了,因为你将神猪运回去的时候,你只能保证这个时候他们不打架
所以我们要做的工作就是去掉两只猪,让剩下的没有交集
也就是将每一只猪连接,去掉两只猪的话,可以构成一个二分图
可以直接枚举这两个点来判断
正解是,枚举其中一个点,便利一遍整个图,看可不可以删掉另外一个点使得构成二分图
这样的话这个点必须在所有的奇数环上,直接判断就好了
并且这个点不能同时被一个奇环和一个偶环跨越
跨越的意思是指去掉端点的跨越
至于为什么,因为一个奇环和一个偶环可以构成一个新的奇环
但是这个奇环和偶环必须一端在父亲那边,另一端在同一颗子树内
如果不在同一颗子树内,就不能构成新的奇环
所以维护奇环偶环的标记时,可以将这个标记标在儿子身上,这样就可以有效避免不在同一颗子树内的情况
AC_code
#include<bits/stdc++.h>
using namespace std;
#define oj
#define mm(x) memset(x,0,sizeof(x))
#define fo(i,x,y) for(int i=(x);i<=(y);i++)
#define fu(i,x,y) for(int i=(x);i>=(y);i--)
const int N=1005;
const int M=3005;
int T,n,m;
struct node{
int a,b,c;
node(){}
bool operator < (node x){
if(a==x.a&&b==x.b)return c<x.c;
if(a==x.a)return b<x.b;
return a<x.a;
}
bool operator == (node x){
return a==x.a&&b==x.b&&c==x.c;
}
}sca[M];
int ain,sum[N];
int to[M*2],nxt[M*2],head[N],rp;
void add_edg(int x,int y){
to[++rp]=y;
nxt[rp]=head[x];
head[x]=rp;
}
int son[N],dep[N],fa[N];
bool cat[N],vie[M*2],via[N],can[N];
int odd[N],cir;
int evo[N],eve[N];//down for one
void dfs(int x,int f,int d){
dep[x]=d;fa[x]=f;via[x]=true;can[x]=true;
for(int i=head[x];i;i=nxt[i]){
if(vie[i])continue;
vie[i]=vie[i^1]=true;
int y=to[i];
if(cat[y])continue;
if(via[y]){
int tmp=dep[x]-dep[y]+1;
if(tmp&1)odd[x]++,odd[fa[y]]--,cir++;
if(tmp&1)evo[x]++,evo[son[y]]--;
else eve[x]++,eve[son[y]]--;
continue;
}
son[x]=y;dfs(y,x,d+1);
if(eve[y]&&evo[y])can[x]=false;
eve[x]+=eve[y],evo[x]+=evo[y],odd[x]+=odd[y];
}
}
signed main(){
#ifdef oj
freopen("river.in","r",stdin);
freopen("river.out","w",stdout);
#endif
scanf("%d",&T);
while(T--){
scanf("%d%d",&n,&m);
memset(sum,0,sizeof(sum));
fo(i,1,m)scanf("%d%d%d",&sca[i].a,&sca[i].b,&sca[i].c);
sort(sca+1,sca+m+1);m=unique(sca+1,sca+m+1)-sca-1;
fo(i,1,m)sum[sca[i].a]++,sum[sca[i].b]++,sum[sca[i].c]++;
int flag=0;fo(i,1,n)if(sum[i]==m)flag++,ain=i;
if(!flag){printf("no\n");continue;}
if(flag>1){printf("sbyes\n");continue;}
flag=0;rp=1;mm(head);mm(cat);
fo(i,1,m){
if(sca[i].a==ain)add_edg(sca[i].b,sca[i].c),add_edg(sca[i].c,sca[i].b);
if(sca[i].b==ain)add_edg(sca[i].a,sca[i].c),add_edg(sca[i].c,sca[i].a);
if(sca[i].c==ain)add_edg(sca[i].b,sca[i].a),add_edg(sca[i].a,sca[i].b);
}
fo(i,1,n){
cat[i]=true;
mm(via);mm(vie);mm(can);
mm(odd);mm(eve);mm(evo);cir=0;
fo(k,1,n)if(!cat[k]&&!via[k])dfs(k,0,1);
fo(k,1,n){
if(k==i||!can[k])continue;
if(odd[k]==cir){printf("yes\n");goto sb;}
}
cat[i]=false;
}
printf("no\n");sb:;
}
}