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;
}

浙公网安备 33010602011771号