A. Goodbye, Ziyin! 【树】
题意:给出一颗无根树,询问有多少个点以它为根时是棵二 叉树。
思路:首先,只有度小于等于3的结点才能算入答案;同时,如果有结点度数为大于等于4,那么不可能为二叉树,直接输出0。
注意:快读输入,不然会超时
代码:
#include<bits/stdc++.h>
using namespace std;
vector<int> vec[1000006];
inline int read(){
int x=0,f=1;
char ch=getchar();
while(ch<'0'||ch>'9'){
if(ch=='-')
f=-1;
ch=getchar();
}
while(ch>='0'&&ch<='9'){
x=(x<<1)+(x<<3)+(ch^48);
ch=getchar();
}
return x*f;
}
int main()
{
int n;n=read();int ans=0;
for(int i=1;i<n;i++){
int u,v;u=read();v=read();
vec[u].push_back(v);
vec[v].push_back(u);
}
bool flag=0;
for(int i=1;i<=n;i++){
if(vec[i].size()>=4){flag=1;break;}
if(vec[i].size()<3)ans++;
}
if(flag)cout<<0<<'\n';
else cout<<ans<<'\n';
return 0;
}
J. Circular Billiard Table 【计算几何 数学】
思路:从样例可以得出,目标是 180*x=a/b*y, 求的是y,y是整数,所以x最小,且使得y是整数。y=180*b*x/a,可以看出,为了使y是整数,x=a/__gcd(180b,a),所以y=180b/__gcd(180b,a)。最后输出答案y-1。
#include<bits/stdc++.h>
using namespace std;
#define int long long
signed main()
{
int T;cin>>T;
while(T--){
int n,m;cin>>n>>m;
m=180*m;
cout<<m/__gcd(n,m)-1<<endl;
}
}
G. Shinyruo and KFC 【组合数】
思路:目标是求出,输出mj在[1,j]的所有情况
初步设想是先把所有阶乘求出来,求出 所有ai的阶乘 的乘积的逆元,然后再每一个mj的情况下,用快速幂求出m的阶乘的n次方,之后n次乘法求出(mj-ai)的阶乘。但是时间复杂度是O(mn),会超时。
优化一下,发现a的总和是1e5,所以有很多重复的a[i]值,用map存一下,最后用快速幂乘起来就可以了
代码:
#include<bits/stdc++.h>
using namespace std;
#define int long long
int pre[100005];
int a[50005];
map<int,int>mp;
const int mod=998244353;
long long binpow(long long a, long long b, long long m) {
a %= m;
long long res = 1;
while (b > 0) {
if (b & 1) res = (__int128)res * a % m;
a = (__int128)a * a % m;
b >>= 1;
}
return res;
}
signed main()
{
pre[0]=1;
int n,m;cin>>n>>m;
for(int i=1;i<=1e5;i++){pre[i]=pre[i-1]*i%mod;}
int maxx=0;int fb=1;
for(int i=1;i<=n;i++){
cin>>a[i];maxx=max(maxx,a[i]);
fb=fb*pre[a[i]]%mod;mp[a[i]]++;
}//分母z
int nfb=binpow(fb,mod-2,mod);
for(int i=1;i<=m;i++){
if(i<maxx){cout<<0<<'\n';continue;}
int za=binpow(pre[i],n,mod);
int fa=1;
//优化部分:
for(auto v:mp){
fa=fa*binpow(pre[i-v.first],v.second,mod);
fa=fa%mod;
}
int nfa=binpow(fa,mod-2,mod);
cout<<za*nfa%mod*nfb%mod<<'\n';
}
return 0;
}
D. Period
题意:给你一个字符串,q次查询,每次查询会将字符串中的一个字符修改为#,求在新串中可以选出几种长度不同的前后缀,使得前后缀相同
注意:输入取消同步,不然会超时
思路:用字符串哈希直接暴力比较前后缀是否相同
代码:
#include<bits/stdc++.h>
using namespace std;
const int N = 1e6 + 5;
const unsigned long long base = 13331;
string s;int n;
unsigned long long has[N];
unsigned long long p[N];
void init(){
p[0]=1;has[0]=0;
n=s.size()-1;
for(int i=1;i<=n;i++){
p[i]=p[i-1]*base;
has[i]=has[i-1]*base+(s[i]-'a');
}
}
unsigned long long get(int l, int r, unsigned long long g[]){
return g[r]-g[l-1]*p[r-l+1];
}
int ans[1000006]={0};
int main()
{
ios::sync_with_stdio(0);cin.tie(0);
cin>>s;s=" "+s;init();
int q;cin>>q;
for(int i=1;i<=n/2;i++){
if(get(1,i,has)==get(n-i+1,n,has)) ans[i]=ans[i-1]+1;
else ans[i]=ans[i-1];
}
for(int i=1;i<=q;i++){
int pos;cin>>pos;
if(pos<=n/2)cout<<ans[pos-1]<<'\n';
else {
pos=n-pos;cout<<ans[pos]<<'\n';
}
}
return 0;
}