思路:
很显然答案是(1-1/(n^m))%mod,因为是除法取模所以是(n^m - 1)*inv(n^m)即可。这题卡常,如果快速幂用两次必超时,用一次就可以过。
代码:
#include<iostream> #include<vector> #include<map> #include<string> #include<cstring> #include<queue> #include<algorithm> #include<set> #include<stack> using namespace std; typedef long long ll; ll mod = 1e9 + 7; //1 - (1/n)^m ll ksm(ll a,ll b){ ll res = 1; while(b){ if(b & 1)res = res * a % mod; b >>= 1; a = a * a % mod; } return res; } ll inv(ll x){ return ksm(x,mod - 2); } void solved(){ ll n,m;scanf("%lld%lld",&n,&m); ll ans = ksm(n,m); printf("%lld\n", (ans - 1) * inv(ans) % mod); } int main(){ int t; while(scanf("%d",&t) != EOF && t > 0){ while(t--) solved(); } return 0; }
思路:打表找规律
可以发现abs(x-y)%3=0必败,其他必胜。
代码:
#include<iostream> #include<vector> #include<map> #include<string> #include<cstring> #include<queue> #include<algorithm> #include<set> #include<stack> using namespace std; typedef long long int ll; void solved(){ int x,y; scanf("%d%d",&x,&y); int s = abs(x - y); if(x == 0 && y == 0){ cout<<"awsl"<<endl; return ; } if(s % 3 == 0){ cout<<"awsl"<<endl; }else{ cout<<"yyds"<<endl; } } int main(){ int t; while(scanf("%d",&t) != EOF){ while(t--){ solved(); } } return 0; }
思路:
a&b=y说明a,b的二进制至少大于等于y,所以a+b=x>=2y才有有结果,否则输出-1,a^b为x-全部二进制位相同的即x-2y,并且(x-2y)&y!=0才行因为当x=3,y=1,这种也是不符合情况的。
代码:
#include<iostream> #include<vector> #include<map> #include<string> #include<cstring> #include<queue> #include<algorithm> #include<set> #include<stack> using namespace std; typedef long long int ll; void solved(){ ll x,y;scanf("%lld%lld",&x,&y); if(x < 2 * y || ((x - 2 * y) & y) != 0){ cout<<"-1"<<endl;return ; } cout<<(x - 2 * y)<<endl; } int main(){ int t;scanf("%d",&t); while(t--) solved(); }
思路:
暴力比较+KMP就行了。
代码:
#include<iostream> #include<vector> #include<map> #include<string> #include<cstring> #include<queue> #include<algorithm> #include<set> #include<stack> using namespace std; typedef long long int ll; const int maxn = 2e5 + 10; int next[maxn]; vector<int> getnext(string t){ vector<int>next(t.size()); for(int i=1,k=0;i<t.size();i++){ while(k>0&&t[i]!=t[k]){ k=next[k-1]; } if(t[i]==t[k]){ next[i]=++k; }else{ next[i]=k; } } return next; } int kmp(string t,string s){ int res = 0; vector<int>next=getnext(t); for(int i=0,k=0;i<s.size();i++){ while(k>0&&s[i]!=t[k]){ k=next[k-1]; } if(t[k]==s[i]){ k++; res = max(res,k); } if(k==t.size()){ return t.size(); } } return res; } void solved(){ string t,s; cin>>t; getnext(t); int n;scanf("%d",&n); int ans = 0; for(int i = 1; i <= n; i++){ cin>>s; ans += kmp(t,s); } printf("%d\n",ans); } int main(){ solved(); }
思路:
点与点之间建立双向边权为走路的时间,然后每个车站可以停的地方建立单向边,从源点s到汇点跑最短路即可。
为什么不能建立单向边呢?
随便举个例子就hack了。
代码:
#include<iostream> #include<vector> #include<map> #include<string> #include<cstring> #include<queue> #include<algorithm> #include<set> #include<stack> using namespace std; typedef long long int ll; const int maxn = 2e5 + 10; struct edge{ int v,w,next; }e[maxn << 2]; int Time[maxn]; vector<int>G[maxn]; int head[maxn],tot; void add(int u,int v,int w){ e[++tot].v = v; e[tot].w = w; e[tot].next = head[u]; head[u] = tot; } ll dis[maxn]; struct node{ ll id,dis; bool operator < (const node &a)const{ return dis > a.dis; } }; void dij(int s,int t){ priority_queue<node>st; st.push(node{s,0}); dis[s] = 0; while(!st.empty()){ node cur = st.top();st.pop(); ll u = cur.id; ll di = cur.dis; if(cur.dis != dis[cur.id])continue; for(int i = head[u]; i; i = e[i].next){ int v = e[i].v; if(dis[v] > dis[u] + e[i].w){ dis[v] = dis[u] + e[i].w; st.push(node{v,dis[v]}); } } } cout<<dis[t]<<endl; } void solved(){ int n,m,s,t,T;scanf("%d%d%d%d%d",&n,&m,&s,&t,&T); for(int i = 1; i <= n; i++)dis[i] = 1e9; for(int i = 1; i <= m; i++){ scanf("%d",&Time[i]); } for(int i = 1; i <= n; i++){ if(i < n){ add(i + 1,i,T); add(i,i + 1,T); } int x;scanf("%d",&x); if(G[x].size() >= 1){ add(G[x].back(),i,Time[x]); } G[x].push_back(i); } dij(s,t); } int main(){ solved(); return 0; }
思路:
很显然找最大连通块就行了,枚举顶点然后dfs跑它的连通块,相等的也记录一下。
时间复杂度O(n + m)。虽然枚举了顶点但是实际上只跑了一遍图。
代码:
#include<iostream> #include<vector> #include<map> #include<string> #include<cstring> #include<queue> #include<algorithm> #include<set> #include<stack> using namespace std; const int maxn = 3e5 + 10; int a[maxn]; vector<int>G[maxn]; bool vis[maxn]; int cnt; vector<int>res; void dfs(int u,int color,int f){ for(int i = 0; i < G[u].size(); i++){ int v = G[u][i]; if(v == f)continue; if(!vis[v] && a[v] == color){ vis[v] = true; cnt++; res.push_back(v); dfs(v,color,u); } } } void solved(){ int n;scanf("%d",&n); for(int i = 1; i <= n; i++)scanf("%d",&a[i]); for(int i = 1; i <= n - 1; i ++){ int u,v;scanf("%d%d",&u,&v); G[u].push_back(v); G[v].push_back(u); } cnt = 1; int ans = 0; vector<int>SS; vector<int>add; for(int i = 1; i <= n; i++){ if(!vis[i]){ res.push_back(i); dfs(i,a[i],-1); if(cnt == ans){ for(int k = 0; k < res.size(); k++){ add.push_back(res[k]); } } if(cnt > ans){ ans = max(ans,cnt); SS = res; add.clear(); } cnt = 1; res.clear(); } } vector<int>cur; for(int i = 0; i < SS.size(); i++){ cur.push_back(SS[i]); } for(int i = 0; i < add.size(); i++){ cur.push_back(add[i]); } sort(cur.begin(),cur.end()); printf("%d\n",(int)cur.size()); for(int i = 0; i < cur.size(); i++){ printf("%d ",cur[i]); } } int main(){ solved(); return 0; }
思路:
dp[i][j] = dp[i - 1][j] + dp[i][j - 1]
不过这里求的是和的不同的个数,我们可以加一个维度表示能否得到这个数字,比如dp[i][j][x]就是(1,1)到(i,j)能不能得到x,true表示可以,false表示不行。转移方程为 dp[i][j][x] |= dp[i - 1][j][(x - a[i][j] + mod) % mod] | dp[i][j - 1][(x - a[i][j] + mod) % mod]。
最后枚举i从0到1e4 + 6找出dp[n][m][i]为真的计数即可。
代码:
#include<iostream> #include<vector> #include<map> #include<string> #include<cstring> #include<queue> #include<algorithm> #include<set> #include<stack> using namespace std; typedef long long int ll; int a[1000][1000]; bool dp[110][110][20000]; int mod = 1e4 + 7; int n,m; void solved(){ scanf("%d%d",&n,&m); for(int i = 1; i <= n; i++){ for(int j = 1; j <= m; j++){ scanf("%d",&a[i][j]); a[i][j] %= mod; } } dp[1][1][a[1][1]] = true; for(int i = 1; i <= n; i++){ for(int j = 1; j <= m; j++){ for(int m = 0; m < mod; m++){ if(i - 1 >= 1) dp[i][j][m] |= dp[i - 1][j][(m - a[i][j] + mod) % mod]; if(j - 1 >= 1) dp[i][j][m] |= dp[i][j - 1][(m - a[i][j] + mod) % mod]; } } } int ans = 0; for(int i = 0; i < mod; i++){ if(dp[n][m][i])ans++; } cout<<ans<<endl; } int main(){ solved(); }
思路:暴力模拟(偷懒了不想写了参考了一下别人的代码)
代码:
#include<iostream> #include<vector> #include<map> #include<string> #include<cstring> #include<queue> #include<algorithm> #include<set> #include<stack> using namespace std; typedef long long int ll; const int maxn = 2e6 + 10; char s[maxn]; int n; int i; ll dfs(){ ll ans = 0,num = 0; for(; i <= n;i++){ ll cnt = 0; while(i <= n && isdigit(s[i])) cnt = cnt * 10 + (s[i] - '0'),i++; ans += num * (cnt > 0 ? cnt : 1); num = 0; if(isalpha(s[i])){ num = (s[i] - 'A' + 1); }else if(s[i] == '('){ i++; num = dfs(); }else break; } ans += num; return ans; } int main(){ scanf("%s",s + 1); n = strlen(s + 1); i = 1; cout<<dfs()<<endl; return 0; }