150A Win or Freeze
传送门
数论水题
题意:给一个数q,写出q的因子p,并用p替换q,p不能等于q或1,谁先不能写谁就赢(注意胜负条件,de了半天发现题意看错了)
很明显,谁拿到质数谁就赢了,那就是质因子分解裸题啦
如果q是两个质数的乘积,那么无论怎么写都是对手第一个得到质数,必输
其他情况下,如果质因子数>=2,任意选两个即可,如果是1,就输出质因子的平方,如果本身是质数或一,输出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
| #include<bits/stdc++.h> using namespace std; typedef long long ll; #define IOS ios_base::sync_with_stdio(false);cin.tie(0); #define maxn 300005 #define for_(i,n) for(ll (i)=1;(i)<=(n);i++) vector<ll> ans; int main(){ IOS ll q; cin>>q; ll tmp=q; for (int i = 2; i <=sqrt(tmp) ; ++i) { if(q%i==0){ while(q%i==0)q/=i; ans.push_back(i); } } if(q>1)ans.push_back(q); if(ans.size()>2){ cout<<"1"<<endl; cout<<ans[0]*ans[1]; }else{ if(ans.size()==2){ if(tmp!=ans[0]*ans[1]){cout<<1<<'\n'<<ans[0]*ans[1];} else cout<<2; } else if(ans.size()==1){ if (tmp!=ans[0]){ if(tmp!=ans[0]*ans[0])cout<<1<<'\n'<<ans[0]*ans[0]; else cout<<2; } else cout<<1<<"\n"<<0; } else cout<<1<<'\n'<<0; } return 0; }
|
776D The Door Problem
传送门
并查集水题
很明显用洛谷关押罪犯的思路即可
关押罪犯
题意:每个门有其初始状态并由两个开关控制,每个开关可控制多个门,每次使用开关会使其控制的门的状态取反(开->关,关->开),询问能否使所有的门都变成开。
对每个门考虑,如果是开,那么该门的两个开关要么都使用,要么都不使用,如果是关,那么两个开关必须使用其中一个(该情况下,假设两个开关互为“敌人”)。
显然就是并查集的思路了,如果是开,合并两个开关并合并两个开关的“敌人”,如果是关,将每个开关分别和另一个开关的“敌人”集合合并。
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
| #include<bits/stdc++.h> using namespace std; typedef long long ll; #define IOS ios_base::sync_with_stdio(false);cin.tie(0); #define maxn 100005 #define for_(i,n) for(ll (i)=1;(i)<=(n);i++) int f[maxn],enemy[maxn]; int findfa(int x){ if(x==f[x])return x; else { f[x]=findfa(f[x]); return f[x]; } } void mergefa(int a,int b){ int fa=findfa(a),fb=findfa(b); if(fa==fb)return ; else{ f[fa]=fb; return ; } } vector<int> s[maxn]; int r[maxn]; int main(){ IOS int n,m; cin>>n>>m; for_(i,n)cin>>r[i]; for_(i,m){ int x; cin>>x; while(x--){ int a; cin>>a; s[a].push_back(i); } } for_(i,m)f[i]=i; for_(i,n){ int a=s[i][0],b=s[i][1]; if(r[i]==1){ mergefa(a,b); if(enemy[a]!=0&&enemy[b]!=0)mergefa(enemy[a],enemy[b]); else if(!enemy[a])enemy[a]=findfa(enemy[b]); else if(!enemy[b])enemy[b]=findfa(enemy[a]); } if(r[i]==0){ if(!enemy[a])enemy[a]=findfa(b); else f[findfa(enemy[a])]=findfa(b); if(!enemy[b])enemy[b]=findfa(a); else f[findfa(enemy[b])]=findfa(a); } } for_(i,n){ int a=s[i][0],b=s[i][1]; if(r[i]==0) if(findfa(a)==findfa(b)){ cout<<"NO"; return 0; } if(r[i]==1) if(findfa(enemy[a])==findfa(b)||findfa(enemy[b])==findfa(a)){ cout<<"NO"; return 0; } } cout<<"YES"; return 0; }
|
721C Journey
传送门
DAG+dp
题意:DAG里每条路有一个权值代表时间,问在时间T内,从1走到n最多可以游览多少景点(我也想旅游(悲))。
之前没怎么做过dag上的dp,然后写个dfs还T了QAQ。
(百度到一般是拓扑排序+dp,具体原因等我学了再来填坑吧)
可以考虑dp[i][j]代表走到景点i且一共游览了j个景点的最小用时,由于还要输出方案,考虑用一个pre二维数组记录。如果dp[i][j]>dp[x][j-1]+w,那么pre[i][j]=x。
转移完成后,从n到2遍历dp[n][i],找出符合时间小于T的i的最大值,输出i,然后沿着pre数组一路找,并且把路上的景点存到栈里。最后输出栈里元素即可。
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
| #include<bits/stdc++.h> using namespace std; typedef long long ll; #define IOS ios_base::sync_with_stdio(false);cin.tie(0); #define maxn 5005 #define inf 1000000002 #define for_(i,n) for(ll (i)=1;(i)<=(n);i++) int n,m,t; struct node{ int v,w; }; vector<node> g[maxn]; int dp[maxn][maxn]; int pre[maxn][maxn]; int de[maxn]; stack<int> ans; queue<int> q; int main(){ IOS cin>>n>>m>>t; for_(i,m){ int u,v; int ti; cin>>u>>v>>ti; g[u].push_back({v,ti});de[v]++; }
while(q.size()!=n){ for_(i,n){ if(de[i]==0){ de[i]--; q.push(i); for (auto j:g[i]){ de[j.v]--; } } } } for_(i,n)for_(j,n)dp[i][j]=inf; dp[1][1]=0; while(!q.empty()){ int now=q.front(); q.pop(); for(auto i:g[now]){ int v=i.v,w=i.w; for_(j,n-1){ if(dp[now][j]+w<dp[v][j+1]){ dp[v][j+1]=dp[now][j]+w; pre[v][j+1]=now; } } } } for (int k = n; k >=2 ; --k) { if(dp[n][k]<=t){ cout<<k<<endl; int i=n,tmp=k; while(i!=0){ ans.push(i); i=pre[i][tmp]; tmp--; } break; } } while(!ans.empty()){ cout<<ans.top()<<" "; ans.pop(); } return 0; }
|
这里度数–可以换成开一个vis数组。
(注意空间限制,开ll会mle。