題目來源:https://ac.nowcoder.com/acm/contest/3002
實力只有八題,覺得發揮的比較好了。(也許今晚會補題 也許明天,保證不咕~)。
upd: 更新完畢 ~ 請放心食用~
A - honoka和格點三角形
假如一邊平行x軸,那分兩種情況 此邊長爲2,此邊長爲1
平行y軸同理,最後發現這兩種情況之和多算了 一邊平行x軸另一邊平行y軸的情況
減去就完事了(多出來的就是 1x2的矩形數量的4倍)
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<stack>
#include<queue>
#include<vector>
#include<set>
#include<map>
#include<string>
#define ls k<<1,l,mid
#define rs k<<1|1,mid+1,r
#define mp(x,y) make_pair(x,y)
#define r(x) read(x)
#define rrr(x,y,z) read(x);read(y);read(z)
#define FOR(i,l,r) for(int i=l;i<=r;i++)
using namespace std;
typedef long long LL;
typedef pair<int,int> pt;
const int N=1e6+5;
const int M=2e3+5;
const int INF=0x7fffffff;
const int mod=1e9+7;
const double eps=1e-8;
const double pi=acos(-1);
LL n,m;
template<class T>
inline void read(T &x)
{
char c; x=1;
while((c=getchar())<'0'||c>'9') if(c=='-') x=-1;
T res=c-'0';
while((c=getchar())>='0'&&c<='9') res=res*10+c-'0';
x*=res;
}
int main()
{
r(n); r(m);
LL ans=0;
//平行x軸 長爲2
ans=(ans+2ll*(m-2)%mod*m%mod)%mod; //邊上的兩個
if(n>2) ans=(ans+2ll*(n-2)%mod*(m-2)%mod*m%mod)%mod;
//長爲1
ans=(ans+1ll*min(4ll,2ll*(n-2))*(m-1)%mod*m%mod)%mod;
if(n>4) ans=(ans+2ll*(n-4)%mod*(m-1)%mod*m%mod)%mod;
//cout<<ans<<endl;
swap(n,m);
ans=(ans+2ll*(m-2)%mod*m%mod)%mod; //邊上的兩個
if(n>2) ans=(ans+2ll*(n-2)%mod*(m-2)%mod*m%mod)%mod;
//長爲1
ans=(ans+1ll*min(4ll,2ll*(n-2))*(m-1)%mod*m%mod)%mod;
if(n>4) ans=(ans+2ll*(n-4)%mod*(m-1)%mod*m%mod)%mod;
//cout<<ans<<endl;
LL num=((n-1)*(m-2)%mod+(m-1)*(n-2)%mod)%mod;
ans=(ans-num*4ll%mod+mod)%mod;
cout<<ans<<endl;
return 0;
}
B - kotori和bangdream
這題題目坑了我,居然只有兩種情況 我以爲有n+1種情況…不難
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<stack>
#include<queue>
#include<vector>
#include<set>
#include<map>
#include<string>
#define ls k<<1,l,mid
#define rs k<<1|1,mid+1,r
#define mp(x,y) make_pair(x,y)
#define r(x) read(x)
#define rrr(x,y,z) read(x);read(y);read(z)
#define FOR(i,l,r) for(int i=l;i<=r;i++)
using namespace std;
typedef long long LL;
typedef pair<int,int> pt;
const int N=1e6+5;
const int M=2e3+5;
const int INF=0x7fffffff;
const int mod=998244353;
const double eps=1e-8;
const double pi=acos(-1);
LL n,m;
int f[N];
template<class T>
inline void read(T &x)
{
char c; x=1;
while((c=getchar())<'0'||c>'9') if(c=='-') x=-1;
T res=c-'0';
while((c=getchar())>='0'&&c<='9') res=res*10+c-'0';
x*=res;
}
int main()
{
int a,b,x;
rrr(n,x,a); r(b);
double xx=x*1.0/100;
double ans=n*a*xx+n*b*(1-xx);
printf("%.2f\n",ans);
return 0;
}
C - umi和弓道
還是分兩種情況討論,方法類似 就只說板子在x軸上吧
如果x0*x[ i ]>0說明 板子不可能擋住這個點,忽略就行,其他的點都有可能通過x軸上的板子阻擋箭。設點(x0,y0)與(x[ i ],y[ i ])連起來和x軸交於點p,那如果p在板子上就可以擋住此點了。 我們只需要擋住n-k個點,尺取就ok了。
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<stack>
#include<queue>
#include<vector>
#include<set>
#include<map>
#include<string>
#define ls k<<1,l,mid
#define rs k<<1|1,mid+1,r
#define mp(x,y) make_pair(x,y)
#define r(x) read(x)
#define rrr(x,y,z) read(x);read(y);read(z)
#define FOR(i,l,r) for(int i=l;i<=r;i++)
using namespace std;
typedef long long LL;
typedef pair<int,int> pt;
const int N=1e6+5;
const int M=2e3+5;
const int INF=0x7fffffff;
const int mod=1e9+7;
const double eps=1e-8;
const double pi=acos(-1);
LL n,m;
double x[N],y[N];
double f[N];
template<class T>
inline void read(T &x)
{
char c; x=1;
while((c=getchar())<'0'||c>'9') if(c=='-') x=-1;
T res=c-'0';
while((c=getchar())>='0'&&c<='9') res=res*10+c-'0';
x*=res;
}
int main()
{
double x0,y0;
scanf("%lf%lf",&x0,&y0);
r(n); r(m);
FOR(i,1,n){
scanf("%lf%lf",&x[i],&y[i]);
}
m=n-m;
double ans1=2e10;
int cnt=0;
FOR(i,1,n){
if(y[i]*y0<0){
f[++cnt]=x0-y0*(x0-x[i])/(y0-y[i]);
}
}
sort(f+1,f+cnt+1);
//FOR(i,1,cnt){
// cout<<f[i]<<' ';
//}
//cout<<endl;
FOR(i,1,cnt-m+1){
ans1=min(f[i+m-1]-f[i],ans1);
}
//x板子
double ans2=2e10;
cnt=0;
FOR(i,1,n){
if(x[i]*x0<0){
f[++cnt]=y0-x0*(y0-y[i])/(x0-x[i]);
}
}
sort(f+1,f+cnt+1);
//FOR(i,1,cnt){
// cout<<f[i]<<' ';
//}
//cout<<endl;
FOR(i,1,cnt-m+1){
ans1=min(f[i+m-1]-f[i],ans1);
}
//cout<<ans1<<' '<<ans2<<endl;
if(ans1==2e10&&ans2==2e10) cout<<-1<<endl;
else printf("%.8f\n",min(ans1,ans2));
//y板子
return 0;
}
D - hanayo和米飯
這題很水啊,想象成一個桶,哪個桶沒有就是哪個…
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<stack>
#include<queue>
#include<vector>
#include<set>
#include<map>
#include<string>
#define ls k<<1,l,mid
#define rs k<<1|1,mid+1,r
#define mp(x,y) make_pair(x,y)
#define r(x) read(x)
#define rrr(x,y,z) read(x);read(y);read(z)
#define FOR(i,l,r) for(int i=l;i<=r;i++)
using namespace std;
typedef long long LL;
typedef pair<int,int> pt;
const int N=1e6+5;
const int M=2e3+5;
const int INF=0x7fffffff;
const int mod=998244353;
const double eps=1e-8;
const double pi=acos(-1);
LL n,m;
int f[N];
template<class T>
inline void read(T &x)
{
char c; x=1;
while((c=getchar())<'0'||c>'9') if(c=='-') x=-1;
T res=c-'0';
while((c=getchar())>='0'&&c<='9') res=res*10+c-'0';
x*=res;
}
int main()
{
r(n);
FOR(i,1,n-1){
int a;
r(a);
f[a]++;
}
FOR(i,1,n){
if(f[i]==0){
cout<<i<<endl;
break;
}
}
return 0;
}
E - rin和快速迭代
找n的因子個數只需要sqrt(n)次判斷 就算是最大的n=1e12 開方之後是1e6
再開方 1e3 哪怕 還需要開1e3次方 也不會超時。
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<stack>
#include<queue>
#include<vector>
#include<set>
#include<map>
#include<string>
#define ls k<<1,l,mid
#define rs k<<1|1,mid+1,r
#define mp(x,y) make_pair(x,y)
#define r(x) read(x)
#define rrr(x,y,z) read(x);read(y);read(z)
#define FOR(i,l,r) for(int i=l;i<=r;i++)
using namespace std;
typedef long long LL;
typedef pair<int,int> pt;
const int N=1e6+5;
const int M=2e3+5;
const int INF=0x7fffffff;
const int mod=998244353;
const double eps=1e-8;
const double pi=acos(-1);
LL n,m;
int f[N];
template<class T>
inline void read(T &x)
{
char c; x=1;
while((c=getchar())<'0'||c>'9') if(c=='-') x=-1;
T res=c-'0';
while((c=getchar())>='0'&&c<='9') res=res*10+c-'0';
x*=res;
}
int hhh(LL x)
{
int ans=0;
FOR(i,1,sqrt(x)){
if(x%i==0){
if(i==sqrt(x)) ans++;
else ans+=2;
}
}
return ans;
}
int main()
{
r(n);
LL now=n;
int ans=0;
while(1){
now=hhh(now);
if(now==2){
cout<<ans+1<<endl;
break;
}
//cout<<now<<endl;
ans++;
}
return 0;
}
F - maki和tree
我覺得這題很有意思,我的做法是帶權並查集 開始的並查集就是所有白點相連即屬於一個集合,然後**加一個數量權**表示這個集合有多少個點。對於每個黑點,假如它連着x個白點集合 這個不難算吧#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<stack>
#include<queue>
#include<vector>
#include<set>
#include<map>
#include<string>
#define ls k<<1,l,mid
#define rs k<<1|1,mid+1,r
#define mp(x,y) make_pair(x,y)
#define r(x) read(x)
#define rrr(x,y,z) read(x);read(y);read(z)
#define FOR(i,l,r) for(int i=l;i<=r;i++)
using namespace std;
typedef long long LL;
typedef pair<int,int> pt;
const int N=2e5+5;
const int M=2e3+5;
const int INF=0x7fffffff;
const int mod=998244353;
const double eps=1e-8;
const double pi=acos(-1);
LL n,m;
struct edge
{
int to,next;
}e[N];
int head[N<<1];
bool color[N];
char str[N];
int dad[N];
int num[N];
int gg[N];
int cnt;
vector<int> v;
template<class T>
inline void read(T &x)
{
char c; x=1;
while((c=getchar())<'0'||c>'9') if(c=='-') x=-1;
T res=c-'0';
while((c=getchar())>='0'&&c<='9') res=res*10+c-'0';
x*=res;
}
void add_edge(int x,int y)
{
e[++cnt].to=y;
e[cnt].next=head[x];
head[x]=cnt;
}
int seek(int k)
{
return dad[k]==k?k:dad[k]=seek(dad[k]);
}
int main()
{
r(n);
scanf("%s",str+1);
FOR(i,1,n){
dad[i]=i;
num[i]=1;
if(str[i]=='B'){
color[i]=1;
v.push_back(i);
}
else color[i]=0;
}
cnt=0;
FOR(i,1,n-1){
int a,b;
r(a); r(b);
add_edge(a,b);
add_edge(b,a);
if(color[a]==0&&color[b]==0){
int x=seek(a),y=seek(b);
if(x!=y){
dad[x]=y;
num[y]+=num[x];
}
}
}
LL ans=0;
for(int i=0;i<v.size();i++){
int now=v[i];
int cc=0;
LL sum=0;
for(int i=head[now];i;i=e[i].next){
int get=e[i].to;
if(color[get]==0){
int tmp=seek(get);
gg[++cc]=num[tmp];
sum+=num[tmp];
}
}
ans+=sum;
FOR(i,1,cc){
ans+=1ll*gg[i]*(sum-gg[i]);
sum-=gg[i];
}
}
cout<<ans<<endl;
return 0;
}
G - eli和字符串
前綴和+二分 代碼應該好懂
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<stack>
#include<queue>
#include<vector>
#include<set>
#include<map>
#include<string>
#define ls k<<1,l,mid
#define rs k<<1|1,mid+1,r
#define mp(x,y) make_pair(x,y)
#define r(x) read(x)
#define rrr(x,y,z) read(x);read(y);read(z)
#define FOR(i,l,r) for(int i=l;i<=r;i++)
using namespace std;
typedef long long LL;
typedef pair<int,int> pt;
const int N=2e5+5;
const int M=2e3+5;
const int INF=0x7fffffff;
const int mod=998244353;
const double eps=1e-8;
const double pi=acos(-1);
LL n,m;
int f[N][26];
char s[N];
template<class T>
inline void read(T &x)
{
char c; x=1;
while((c=getchar())<'0'||c>'9') if(c=='-') x=-1;
T res=c-'0';
while((c=getchar())>='0'&&c<='9') res=res*10+c-'0';
x*=res;
}
int main()
{
r(n); r(m);
scanf("%s",s+1);
FOR(i,1,n){
FOR(j,0,25){
if(s[i]-'a'==j) f[i][j]=f[i-1][j]+1;
else f[i][j]=f[i-1][j];
}
}
int ans=INF;
FOR(i,1,n){
int l=i,r=n;
int res=INF;
while(l<=r){
int mid=(l+r)>>1;
bool flag=1;
FOR(j,0,25){
if(f[mid][j]-f[i-1][j]>=m){
flag=0;
break;
}
}
if(!flag){
res=mid;
r=mid-1;
}
else l=mid+1;
}
if(res!=INF) ans=min(res-i+1,ans);
}
if(ans==INF) cout<<-1<<endl;
else cout<<ans<<endl;
return 0;
}
H - nozomi和字符串
和上一題一樣…感覺水了 ,前綴和+二分
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<stack>
#include<queue>
#include<vector>
#include<set>
#include<map>
#include<string>
#define ls k<<1,l,mid
#define rs k<<1|1,mid+1,r
#define mp(x,y) make_pair(x,y)
#define r(x) read(x)
#define rrr(x,y,z) read(x);read(y);read(z)
#define FOR(i,l,r) for(int i=l;i<=r;i++)
using namespace std;
typedef long long LL;
typedef pair<int,int> pt;
const int N=2e5+5;
const int M=2e3+5;
const int INF=0x7fffffff;
const int mod=998244353;
const double eps=1e-8;
const double pi=acos(-1);
LL n,m;
int f[N][2];
char s[N];
template<class T>
inline void read(T &x)
{
char c; x=1;
while((c=getchar())<'0'||c>'9') if(c=='-') x=-1;
T res=c-'0';
while((c=getchar())>='0'&&c<='9') res=res*10+c-'0';
x*=res;
}
int main()
{
r(n); r(m);
scanf("%s",s+1);
FOR(i,1,n){
if(s[i]=='1'){
f[i][1]=f[i-1][1]+1;
f[i][0]=f[i-1][0];
}
else{
f[i][0]=f[i-1][0]+1;
f[i][1]=f[i-1][1];
}
}
int ans1=0;
FOR(i,1,n){
int l=i,r=n;
int res=INF;
if(n-i+1<=ans1) break;
while(l<=r){
int mid=(l+r)>>1;
if(f[mid][1]-f[i-1][1]<=m){
l=mid+1;
res=mid;
}
else r=mid-1;
}
//cout<<res<<endl;
if(res!=INF) ans1=max(res-i+1,ans1);
}
int ans2=0;
FOR(i,1,n){
int l=i,r=n;
int res=INF;
if(n-i+1<=ans2) break;
while(l<=r){
int mid=(l+r)>>1;
if(f[mid][0]-f[i-1][0]<=m){
l=mid+1;
res=mid;
}
else r=mid-1;
}
if(res!=INF) ans2=max(res-i+1,ans2);
}
cout<<max(ans1,ans2)<<endl;
return 0;
}
I - nico和niconiconi
此題是補題。參考鏈接:https://www.cnblogs.com/SwiftAC/p/12260779.html
我當時有想過dp,但是就是不知道怎麼轉移 tcl tcl !
類似的字符串切割方法也可以學一下,挺方便的string s(str+i-3,str+i+1);
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<stack>
#include<queue>
#include<vector>
#include<set>
#include<map>
#include<string>
#define ls k<<1,l,mid
#define rs k<<1|1,mid+1,r
#define mp(x,y) make_pair(x,y)
#define r(x) read(x)
#define rrr(x,y,z) read(x);read(y);read(z)
#define FOR(i,l,r) for(int i=l;i<=r;i++)
using namespace std;
typedef long long LL;
typedef pair<int,int> pt;
const int N=3e5+5;
const int M=2e3+5;
const int INF=0x7fffffff;
const int mod=998244353;
const double eps=1e-8;
const double pi=acos(-1);
LL n,m;
char str[N];
LL dp[N];
template<class T>
inline void read(T &x)
{
char c; x=1;
while((c=getchar())<'0'||c>'9') if(c=='-') x=-1;
T res=c-'0';
while((c=getchar())>='0'&&c<='9') res=res*10+c-'0';
x*=res;
}
int main()
{
r(n); LL a,b,c;
rrr(a,b,c);
scanf("%s",str+1);
FOR(i,1,n){
if(i>=4){
string s(str+i-3,str+i+1);
if(s=="nico"){
dp[i]=max(dp[i-4]+a,dp[i]);
}
else dp[i]=max(dp[i],dp[i-1]);
}
if(i>=6){
string s(str+i-5,str+i+1);
if(s=="niconi"){
dp[i]=max(dp[i-5]+b,dp[i]);
}
else dp[i]=max(dp[i],dp[i-1]);
}
if(i>=10){
string s(str+i-9,str+i+1);
if(s=="niconiconi"){
dp[i]=max(dp[i-10]+c,dp[i]);
}
else dp[i]=max(dp[i],dp[i-1]);
}
}
cout<<dp[n]<<endl;
return 0;
}
J - u’s的影響力
這題是個數學題,我不是數學手,搞了一天才搞懂
用到了 矩陣快速冪+歐拉降冪+快速冪
前兩項特判就不說了
從第三項開始 都會呈現一定的規律
f( 3) =x1 * y1 * ab
f( 4) =x1 * y2 * a2b
f( 5) =x2 * y3 * a4
f( 6) =x3 * y5 * a7
設 xx yy aa 分別爲x y a 的冪
再設g(1)=1 g(2)=1 ,當i>3時 g(i)=g(i-1)+g(i-2)
那麼xx=g(n-2) ,yy=g(n-1) aa=g(n)-1 【n>3】
所以我們來一次矩陣快速冪就好了~
構造矩陣:
1 | 1 |
---|---|
0 | 0 |
但是斐波拉契數列到幾十項就快爆了,我們一定要取模,但是怎麼取了?
這裏用到了歐拉降冪 假如我們要求ab ,現在我們用mod=1e9+7,題目也說了mod是個質數,當a<mod時 a一定與mod互質 可以直接降冪。但當a>=mod時,可能出現a=k*mod的情況,我們要提前特判此時 ab%mod=0 即可(我被這裏卡了幾個小時)
最後是個快速冪,我就不說了.
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<stack>
#include<queue>
#include<vector>
#include<set>
#include<map>
#include<string>
#define ls k<<1,l,mid
#define rs k<<1|1,mid+1,r
#define mp(x,y) make_pair(x,y)
#define r(x) read(x)
#define rrr(x,y,z) read(x);read(y);read(z)
#define FOR(i,l,r) for(int i=l;i<=r;i++)
using namespace std;
typedef long long LL;
typedef pair<int,int> pt;
const int N=1e6+5;
const int M=2e3+5;
const int INF=0x7fffffff;
const int mod=1e9+7;
const double eps=1e-8;
const double pi=acos(-1);
LL n,m;
struct node
{
LL f[3][3];
}t;
template<class T>
inline void read(T &x)
{
char c; x=1;
while((c=getchar())<'0'||c>'9') if(c=='-') x=-1;
T res=c-'0';
while((c=getchar())>='0'&&c<='9') res=res*10+c-'0';
x*=res;
}
node mult(const node &a,const node &b)
{
node res;
FOR(i,1,2)
FOR(j,1,2){
res.f[i][j]=0;
FOR(k,1,2) res.f[i][j]=(res.f[i][j]+a.f[i][k]*b.f[k][j])%(mod-1);
}
return res;
}
LL qpow(LL a,LL p)
{
LL res=1;
while(p){
if(p&1) res=res*a%mod;
a=a*a%mod;
p>>=1;
}
return res;
}
int main()
{
LL x,y,a,b;
rrr(n,x,y); r(a); r(b);
x%=mod; y%=mod; a%=mod; b%=(mod-1);
if(n==1){cout<<x<<endl; return 0;}
else if(n==2){cout<<y<<endl; return 0;}
if(x==0||y==0||a==0){cout<<0<<endl; return 0;}
LL xx,yy,aa;
node now;
now.f[1][1]=now.f[2][2]=1; now.f[1][2]=now.f[2][1]=0;//單位矩陣
t.f[1][1]=t.f[1][2]=t.f[2][1]=1; t.f[2][2]=0; //構造出來的矩陣
n-=2;
while(n){
if(n&1) now=mult(now,t);
t=mult(t,t);
n>>=1;
}
aa=now.f[1][1]+now.f[1][2];
yy=now.f[2][1]+now.f[2][2];
yy=yy%(mod-1);
xx=(aa-yy+(mod-1))%(mod-1);
aa=(aa-1+(mod-1))%(mod-1);
//cout<<xx<<' '<<yy<<' '<<aa<<endl;
LL ans=qpow(x,xx)*qpow(y,yy)%mod*qpow(qpow(a,aa)%mod,b)%mod;
cout<<ans<<endl;
return 0;
}