根据题意可知,求连续两个质数相加除以2向下取整后是否还是质数,因为是连续的两个质数,所以取中位数后一定不会是质数,1除外
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
   | #include <bits/stdc++.h> using namespace std; typedef long long LL; LL t , n; int main() {     scanf("%lld" , &t);     while (t --)     {         scanf("%lld" , &n);         if (n == 1) printf("YES\n");         else printf("NO\n");     }     return 0; }
   | 
 
给定一个字符串,求这个字符串有多少个子序列满足由前缀nunhehheh和k个a(k>0)组成。
例如nunhehhehaaaaaa就是符合要求的,但是nunhehheh和nunhehhehoooaaa是不符合要求的。
这是一个dp模型,求一个字符串的所有子序列中有多少个s(s是一个字符串),这里只是多了后缀a,我们先找字符串包含多少个nunhehheh,开一个dp数组,dp[i]表示匹配到匹配到第k个字符出现了前i个字串的数量,例如dp[1]表示出现n的数量,dp[3]表示出现nun的数量,遍历字符串,将对应的字符,dp[i]=(dp[i-1]+dp[i])%mod
最后dp[9]就是出现nunhehheh的数量,用dp[10]表示前缀nunhehheh和k个a(k>0)组成的字符串数量,考虑给后面加上一个a,那么之前满足条件的字符串可以加a也可以不加,而dp[9]必须加上这个a才能满足条件,所以dp[10]=(dp[10]+dp[9])%mod
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38
   | #include <bits/stdc++.h> #define endl '\n' #define ios ios::sync_with_stdio(0);cin.tie(0);cout.tie(0) using namespace std; typedef long long ll; ll mod=998244353; ll dp[20],T; int main() { 	ios; 	cin>>T; 	while(T--){ 		memset(dp,0,sizeof dp); 		string s; 		cin>>s; 		int len=s.size(); 		for(int i=0;i<len;i++){ 			if(s[i]=='n'){ 				dp[1]++; 				dp[3]=(dp[3]+dp[2])%mod; 			} 			else if(s[i]=='u') dp[2]=(dp[1]+dp[2])%mod; 			else if(s[i]=='h'){	 				dp[9]=(dp[9]+dp[8])%mod; 				dp[7]=(dp[7]+dp[6])%mod; 				dp[6]=(dp[6]+dp[5])%mod; 				dp[4]=(dp[4]+dp[3])%mod; 			} 			else if(s[i]=='e'){ 				dp[5]=(dp[4]+dp[5])%mod; 				dp[8]=(dp[8]+dp[7])%mod; 			} 			else if(s[i]=='a') dp[10]=(dp[10]*2%mod+dp[9])%mod; 		} 		cout<<dp[10]<<endl; 	} 	return 0; }
   | 
 
分类讨论,数学问题,我用小数写的,但是其实用longlong更好,不会有精度问题
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37
   | #include <bits/stdc++.h> #define endl '\n' #define ios ios::sync_with_stdio(0);cin.tie(0);cout.tie(0) using namespace std; typedef long long ll; const ll mod=998244353; int T; double a,b,c,x0,y0,x1,y1,y2; double f1(ll y){ 	return (-b+sqrt(b*b-4*a*(c-y0)))/(2*a); } double f2(ll y){ 	return (-b-sqrt(b*b-4*a*(c-y0)))/(2*a); } double work(double x){ 	return a*x*x+b*x+c; } int main() { 	ios; 	cin>>T; 	while(T--){ 		cin>>a>>b>>c; 		cin>>x0>>x1>>y0>>y1>>y2; 		if(work(x0)==y0 || work(x1)==y0) cout<<"No"<<endl; 		else{ 			double p=-b/(2*a); 			if(work(p)<=y0 || p>=x1 || (f1(y0)>=x0 && f1(y0)<=x1)) cout<<"No"<<endl; 			else if(f2(y0)>x0 && f2(y0)<x1) cout<<"Yes"<<endl; 			else{ 				if(work(x1)<=y2 && f2(y0)>x1 && f2(y0)<x1+x1-x0) cout<<"Yes"<<endl; 				else cout<<"No"<<endl; 			} 		} 	} 	return 0; }
   | 
 
更好的代码如下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
   | #include <bits/stdc++.h> #define ios ios::sync_with_stdio(false), cin.tie(0), cout.tie(0); using namespace std; typedef unsigned long long ull; typedef long long ll; const ll mod = 998244353;
  ll a, b, c, xa, xb, ya, yb, yc;
  ll changdu(ll x){     ll res = a * x * x + b * x + c;     return res; }
  int main() {     ios;     int t;     cin >> t;     while(t --){         cin >> a >> b >> c >> xa >> xb >> ya >> yb >> yc;         ll lena = changdu(xb), lenb = changdu(0 - xa + xb * 2), len = changdu(xa);         if (len <= ya) cout << "No\n";         else if (lena == ya || lena > yc) cout << "No\n";         else if (lena < ya) cout << "Yes\n";         else{             if (lenb >= ya) cout << "No\n";             else cout << "Yes\n";         }     }
      return 0; }
   | 
 
比赛的时候一直在想从边权大的开始出发,把所有能到达这个点的所有点答案加一,利用线段树去维护,但是到后面块太多了,维护不了,于是就搁置了,正解是从边权小的开始枚举,对于当前点,把和这个点相邻的点都合并到当前点,让当前点作为祖先,循环往复,到最后每一个点距离根节点的距离就是答案,原理就是因为是按照点权从小到大枚举的,因此每一个点都不可能越过根节点到达其他分支的节点,所以一个节点可以到达的节点就是这个点距离和根节点之间的点,也就是距离。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67
   | #include <bits/stdc++.h> #define endl '\n' #define ios ios::sync_with_stdio(0);cin.tie(0);cout.tie(0) using namespace std; const int N=2e5+100; struct node{ 	int id,val; }arr[N]; int T,n,u,v; int fa[N],ans[N]; bool vis[N]; vector<int> ve[N]; bool cmp(node a,node b){ 	return a.val<b.val; } int find(int x){ 	if(x==fa[x]) return x; 	else{ 		int tmp=fa[x]; 		fa[x]=find(fa[x]); 		ans[x]+=ans[tmp];	 		return fa[x]; 	} } void init(){ 	for(int i=1;i<=n;i++){ 		fa[i]=i; 		ans[i]=0; 		ve[i].clear();	 		vis[i]=0; 	}  } int main() { 	ios; 	cin>>T; 	while(T--){ 		cin>>n; 		init(); 		for(int i=1;i<n;i++){ 			cin>>u>>v; 			ve[u].push_back(v); 			ve[v].push_back(u); 		} 		for(int i=1;i<=n;i++){ 			cin>>arr[i].val; 			arr[i].id=i; 		} 		sort(arr+1,arr+1+n,cmp); 		for(int i=1;i<=n;i++){ 			int now=arr[i].id; 			for(int j=0;j<ve[now].size();j++){ 				if(vis[ve[now][j]]){ 					int fu=find(ve[now][j]); 					ans[fu]=1; 					fa[fu]=now; 				} 			} 			vis[now]=1; 		} 		for(int i=1;i<=n;i++){ 			find(i); 			cout<<ans[i]+1<<endl; 		} 	} 	return 0; }
   | 
 
Monopoly
$a1,a2,a3…an$
首先求一个前缀和,$S=K*pre[n]+pre[i]$,考虑pre[n]大于0的情况,这个时候pre[i]一定小于等于S,对pre[n]取模,发现S和pre[i]同余,也就是求一个pre[i]使得K最小,并且在K相同条件下i尽可能小,考虑维护n个容器,每一个容器对应一个余数,容器中放置所有同余的前缀和,给定一个x就去相对应的容器中二分找到小于等于x的最大前缀,即是答案。
需要特别注意的是,前缀和可能是负数,而给定的x是负数,这个时候x和前缀和是同余的,但是符号相反,这里需要特别处理一下。
如果pre[n]小于0,则所有数字取反即可。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85
   | #include <iostream> #include <string.h> #include <map> #include <algorithm> #include <vector> #define endl '\n' #define ios ios::sync_with_stdio(0);cin.tie(0);cout.tie(0) using namespace std; const int N=2e5+100; typedef long long ll; int n,m; ll arr[N]; vector<ll> cis[N]; int tot,T; map<ll,int> mp,mp2; void init(){ 	mp.clear(); 	mp2.clear(); 	for(int i=1;i<=tot;i++) cis[i].clear(); 	tot=0; } int main() { 	ios; 	cin>>T; 	while(T--){ 		init(); 		cin>>n>>m; 		for(int i=1;i<=n;i++){ 			cin>>arr[i]; 			arr[i]+=arr[i-1]; 		} 		ll sum=arr[n]; 		int flag=0; 		if(sum<0){ 			for(int i=1;i<=n;i++) arr[i]=-arr[i]; 			sum=-sum; 			flag=1; 		} 		for(int i=1;i<=n;i++) if(!mp2[arr[i]]) mp2[arr[i]]=i;; 		if(sum!=0){ 			for(int i=1;i<=n;i++){ 				ll now=(arr[i]%sum+sum)%sum; 				if(!mp[now]) mp[now]=++tot; 				cis[mp[now]].push_back(arr[i]); 			} 		} 		for(int i=1;i<=tot;i++) sort(cis[i].begin(),cis[i].end()); 		while(m--){ 			ll x; 			cin>>x; 			if(flag) x=-x; 			if(x==0){ 				cout<<0<<endl; 				continue; 			} 			if(sum==0){ 				if(mp2[x]) cout<<mp2[x]<<endl; 				else cout<<-1<<endl; 				continue; 			} 			if(!mp[(x%sum+sum)%sum]){ 				cout<<-1<<endl; 				continue; 			} 			int now=mp[(x%sum+sum)%sum]; 			auto it=upper_bound(cis[now].begin(),cis[now].end(),x); 			if(it==cis[now].begin()) cout<<-1<<endl; 			else{ 				it--; 				cout<<(x-*it)/sum*n+mp2[*it]<<endl; 			} 		} 	} 	return 0; }
 
 
 
 
 
 
 
 
 
   |