19-11-09-∵

先挖个坑,不然多半会忘掉

关于对拍?

大家都是怎么写的呀?

$\text{vim}$玄手又来发广告了。

写下面这个,不用再看一眼对拍:

if(system("diff a.out b.out -b -B -q")){
	puts("WA");
	system("gnome-terminal --command=\"vimdiff a.out b.out\"");
	system("gnome-terminal --command=\"vim 1.in\"");
	return 0;
}

 

只要$\text{wa}$了就突然钻出一个光头弹出两个窗口,就是用$\text{vim}$打开那三个东西,$\text{gedit}$玩家请自行修改。

总结:

T1一看是个$\Theta(N^2)$题。

emm。于是先码一个暴力,然后接着一个贪心。

疯狂对拍$\color{forestgreen}{\text{AC}}$

T2不是很清楚怎么做,然后先写暴力。

T3……写了一个特判,然后就是一大堆测试点分治(可以这很NOIPCSP-S)

状态还行。

27
Miemeng 100
00:00:33
40
00:00:34
55
00:00:34
195
00:00:34

TJ解:

T1:

我的考试方法仿佛伪了……

我当时是枚举中间点直接暴力向左右扫并将相同的合并过来,

所以因为是直接判的长度而不是长度加前缀和,于是有时候不对。

但是因为枚举了不同的$\text{mid}$所以还不能卡掉。

所以它现在还处在半A不A的状态(///▽///)

 

//swap

#include <iostream>
#include <cstring>
#include <cstdio>
#define N 4444

using namespace std;

int len,cn;
char str[N];
int ans=0;
int getmid(int mid){
	int lft=cn,gn=1,lpre=0,rpre=0;
	for(int i=1;i<=len;i++){
		if(lft<i-lpre-1 && lft<i-rpre-1)break;
		if(mid+i>len && mid-i<1)break;
		if(mid+i<=len && lft>=i-lpre-1 && str[mid+i]==str[mid]){
			lft-=(i-lpre-1);
			lpre++;
			gn++;
		}
		if(mid-i>=1 && lft>=i-rpre-1 && str[mid-i]==str[mid]){
			lft-=(i-rpre-1);
			rpre++;
			gn++;
		}
	}
	return gn;
}
int main(){
#ifndef LOCAL
	freopen("swap.in" ,"r",stdin);
	freopen("swap.out","w",stdout);
#endif
	scanf("%d%d%s",&len,&cn,str+1);
	for(int i=1;i<=len;i++){
//		cout<<i<<" "<<getmid(i)<<endl;
		ans=max(getmid(i),ans);
	}
	cout<<ans<<endl;
}

T2

好久没有改完题的快感了……

这个题还是非常可做的qwq

首先我们先码一个暴力。

pua!

$\text{20%}$算法

直接暴力即可。

你可以像这样判断一个数是否是完全平方数。

bool is_sq(LL val){
	double sq=sqrt(val);
	return floor(sq)==ceil(sq);
}

然后你就被卡精了(滑稽

发现精度不够……

bool is_sq(LL val){
	long double sq=sqrt(val);
	return floor(sq)==ceil(sq);
}

好了$1\text{~}10^{18}$都正确了。

但是还有一种更有脑子的做法。

bool is_p2(int va){
    int qva=sqrt(va);
    return qva*qva==va;
}

另$\text{20%}$算法

我们发现有些数很小。

$a_i \leq 1000$

开桶维护即可。

  • 二合一:
//square

#include <iostream>
#include <cstring>
#include <cstdio>
#include <vector>
#include <cmath>
#define N 333333
#define sqA 31632
#define LL long long

using namespace std;

int nn;
LL arr[N];
int ans=0;

bool is_sq(LL val){
	long double sq=sqrt(val);
//	if(floor(sq)==ceil(sq))cout<<sq<<endl;
	return floor(sq)==ceil(sq);
}
namespace _3{
	const int T_Size=1111;
	int tb[T_Size],sqr[T_Size];
	bool mp[T_Size][T_Size];
	void prerun(){
		memset(tb,0,sizeof tb);
		for(int i=1;i<=1000;i++){
			sqr[i]=i*i;
		}
		for(int i=1;i<=1000;i++){
			for(int j=1;j<=1000;j++){
				if(sqr[i]%j==0 && sqr[i]/j<=1000){
					mp[sqr[i]/j][j]=mp[j][sqr[i]/j]=1;
				}
			}
		}
	}
	void work(){
		prerun();
		for(int i=1;i<=nn;i++)
			tb[arr[i]]++;
		for(int i=1;i<=1000;i++){
			if(tb[i]==0)continue;
			for(int j=1;j<=1000;j++){
				if(mp[i][j]==1){
//					cout<<i<<" "<<j<<" "<<tb[i]*tb[j]<<endl;
					if(i!=j)
						ans+=tb[i]*tb[j];
					else
						ans+=tb[i]*(tb[j]-1);
				}
			}
		}
		cout<<ans/2<<endl;
	}
}
int main(){
#ifndef LOCAL
	freopen("square.in" ,"r",stdin);
	freopen("square.out","w",stdout);
#endif
	bool allsm=1;
	scanf("%d",&nn);
	for(int i=1;i<=nn;i++){
		scanf("%lld",arr+i);
		if(arr[i]>1000)allsm=0;
	}
	if(allsm)_3::work();
	else{
		for(int i=1;i<=nn;i++){
			for(int j=i+1;j<=nn;j++){
				if(is_sq(arr[i]*arr[j])){
					ans++;
				}
			}
		}
		cout<<ans<<endl;
	}
}

$\text{70%}$算法

蒟蒻的思维可能到不了这里??(为什么想了却扔掉了啊?

我们发现如果某个数有平方因子,那是没有意义的……

于是求$\sqrt{\max\{a_i\}}$内的质数。

对每个数进行处理,然后排序统计相同的即可。

如果你开桶($\text{map}$)好像会被卡常。

这题还是挺卡常的……

所以少开long long!

#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdio>
#include <vector>
#include <cmath>
#define N 333333
#define SQ 31633

using namespace std;

int nn,arr[N];
bool notp[SQ];
vector <int> pr;
int ans=0;

void getprime(const int lim){
    notp[1]=1;
    for(int i=2;i<=lim;i++){
        if(!notp[i]){
            pr.push_back(i);
            for(int j=i*2;j<=lim;j+=i){
                notp[j]=1;
            }
        }
    }
}
int main(){
#ifndef LOCAL
    freopen("square.in" ,"r",stdin);
    freopen("square.out","w",stdout);
#endif
    int maxn=0;
    cin.sync_with_stdio(false);
    cin>>nn;
    for(int i=1;i<=nn;i++){
        cin>>arr[i];
        maxn=max(maxn,arr[i]);
    }
    getprime(sqrt(maxn)+1);
    for(int i=1;i<=nn;i++){
        int dat=arr[i];
        for(int j=0;j<int(pr.size());j++){
            while(dat%(pr[j]*pr[j])==0)
                dat/=(pr[j]*pr[j]);
            if(dat==1)break;
        }
//      cout<<arr[i]<<" "<<dat<<endl;
        arr[i]=dat;
    }
    int val=1;
    sort(arr+1,arr+nn+1);
    for(int i=1;i<=nn;i++){
//      cout<<arr[i]<<"V"<<val<<endl;
        if(arr[i]==arr[i-1]){
            val++;
        }
        else{
            ans+=val*(val-1)/2;
            val=1;
        }
//      cout<<arr[i]<<"^"<<val<<endl;
    }
    ans+=val*(val-1)/2;
    cout<<ans<<endl;
#ifndef LOCAL
	fclose(stdin);
	fclose(stdout);
#endif
}

$\text{100%}$算法

上面的过程非常优秀了,但是由于$\sqrt{\max\{a_i\}}$还是太巨了,于是还是只有$70$

我们就想简化这个过程,

一个数最多只有一个大于$\sqrt[3]{\max\{a_i\}}$的成平方的因子

那么我们只要想办法解决上面的因子就好了。

于是先用$\sqrt[3]{\max\{a_i\}}$的因子去筛,剩下的判断是否是完全平方数就可以快速处理。

具体细节见代码:

#include <algorithm>
#include <iostream>
#include <cstdio>
#include <vector>
#include <cmath>
#define SQ3 1211
#define N 333333

using namespace std;

int nn,arr[N];
bool notp[SQ3];
vector <int> pr;
long long ans=0;

void getprime(const int lim){
    notp[1]=1;
    for(int i=2;i<=lim;i++){
        if(!notp[i]){
            pr.push_back(i);
            for(int j=i*2;j<=lim;j+=i){
                notp[j]=1;
            }
        }
    }
}
bool is_p2(int va){
    int qva=sqrt(va);
    return qva*qva==va;
}
int main(){
#ifndef LOCAL
    freopen("square.in" ,"r",stdin);
    freopen("square.out","w",stdout);
#endif
    cin.sync_with_stdio(false);
    int maxn=0;
    cin>>nn;
    for(int i=1;i<=nn;i++){
        cin>>arr[i];
        maxn=max(maxn,arr[i]);
    }
    getprime(1100);
    for(int i=1;i<=nn;i++){
        int dat=arr[i];
        for(int j=0;j<int(pr.size());j++){
            while(arr[i]%(pr[j]*pr[j])==0)
                arr[i]/=pr[j]*pr[j];
            while(dat%pr[j]==0)
                dat/=pr[j];
        }
//        cout<<dat<<" "<<arr[i]<<endl;
        if(is_p2(dat))
            arr[i]/=dat;
    }
    sort(arr+1,arr+nn+1);
    int val=1;
    for(int i=1;i<=nn;i++){
        if(arr[i]==arr[i-1])val++;
        else{
            ans+=1ll*val*(val-1)/2;
            val=1;
        }
    }
    ans+=1ll*val*(val-1)/2;
    cout<<ans<<endl;
#ifndef LOCAL
	fclose(stdin);
	fclose(stdout);
#endif
}

T3

好dp题。

那么就好好写个dp柿子。

为了找到合法路径我们可以搞一下非法路径。

于是设$f_i$为以$i$为起点的路径数,记$ways(i,j)$为从$i$到$j$的路径数。

$$f_i=ways(A,i)-\sum \limits_{j}^{j \rightarrow i} f_j \times ways(i,j)$$

简单容斥即可。

#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdio>
#define N 111111
#define D 111
#define LL long long
#define aim(k) po[pn+1][(k)]

using namespace std;

const int Mod=1e9+7,
          Phi=Mod-1;
int dn,pn;
struct POINT{
    int arr[D];
    int & operator [] (const int id){
        return this->arr[id];
    }
    friend bool operator < (const POINT &a,const POINT &b){
        for(int i=1;i<=dn;i++){
            if(a.arr[i] != b.arr[i])
                return a.arr[i] < b.arr[i];
        }
        return 1;
    }
}po[N];
int fac[N*D],inv[N*D];
int dp[N];
LL ans=0;

LL ppow(LL a,LL b){
    a%=Mod;
    b%=Phi;
    LL res=1;
    while(b){
        if(b&1)res=res*a%Mod;
        a=a*a%Mod;
        b>>=1;
    }
    return res;
}
void prerun(){
    int lim=10000000;
    fac[0]=inv[0]=1;
    for(int i=1;i<=lim;i++)
        fac[i]=1ll*fac[i-1]*i%Mod;
    inv[lim]=ppow(fac[lim],Mod-2);
    for(int i=lim-1;i>=1;i--){
        inv[i]=1ll*inv[i+1]*(i+1)%Mod;
    }
}
LL C(LL n,LL m){
    if(n<m)return 0;
    if(m<0 || n<0) return 0;
    return 1ll*fac[n]*inv[m]%Mod*inv[n-m]%Mod;
}
LL getways(int a,int b){
    int sum=0;
    LL dat=1;
    for(int i=1;i<=dn;i++)
        sum+=po[a][i]-po[b][i];
    for(int i=1;i<=dn;i++){
        dat=dat*C(sum,po[a][i]-po[b][i])%Mod;
        sum-=po[a][i]-po[b][i];
    }
    return dat;
}
int main(){
#ifndef LOCAL
    freopen("net.in" ,"r",stdin);
    freopen("net.out","w",stdout);
#endif
    cin.sync_with_stdio(false);
    prerun();
    cin>>dn>>pn;
    for(int i=1;i<=dn;i++)
        cin>>aim(i);
    for(int i=1;i<=pn;i++){
        for(int j=1;j<=dn;j++){
            cin>>po[i][j];
        }
    }
    ans=getways(pn+1,0);
    sort(po+1,po+pn+1);
/*    for(int i=1;i<=pn;i++){
        for(int j=1;j<=dn;j++)
            cout<<po[i][j]<<" ";
        cout<<endl;
    }*/
    for(int i=1;i<=pn;i++){
        dp[i]=getways(i,0);
        for(int j=1;j<i;j++){
            dp[i]=(1ll*dp[i]-1ll*dp[j]*getways(i,j)%Mod+Mod)%Mod;
        }
    }
    for(int i=1;i<=pn;i++){
//        cout<<i<<" "<<dp[i]*getways(pn+1,i)<<endl;
        ans=(ans-1ll*dp[i]*getways(pn+1,i)%Mod+Mod)%Mod;
    }
    cout<<ans<<endl;
}
posted @ 2019-11-09 14:16  Miemeng_麦蒙  阅读(376)  评论(0编辑  收藏  举报

小麦在雨中,蒙蒙的雾气

麦蒙不想有人骚扰他,如果有必要 联系 QQ:1755601414

如果你嫌广告大,那就喷我吧,不是博客园的锅。