A.传递
赛后AC数最多的2016合肥题。赛时没看到是竞赛图,以为是o(n^3)果断放弃
后面才看到。。。一开始想到用补图的2个方向去补原图再判圈,光荣TLE--边数也太多了吧!
后用其他人的判传递法才成功控制时间AC
感觉如果非要判圈,有些数据可以卡dfs
判传递也太简单了。。。从一个点开始覆盖点,如果有2边链且不被传递,到那边的点,会发现还没覆盖,标上2,退出走人
#include <bits/stdc++.h> using namespace std; typedef double db; typedef long long ll; typedef unsigned int uint; typedef unsigned long long ull; const db eps=1e-6; #define lson l, m, rt << 1 #define rson m + 1, r, rt << 1 | 1 #define CLR(a, b) memset(a, b, sizeof(a)) const int N=5000,M=7000000;//2500*2,2500*2499/2*2 int head[N],cnt,n; int to[M],nxt[M]; char vis[N]; void addedge(int u,int v) { to[cnt]=v;nxt[cnt]=head[u];head[u]=cnt++; } int que[N]; bool bfs(int u) { memset(vis,0,sizeof(vis)); int tal=0,hed=0; que[tal++]=u; while(tal!=hed) { int u=que[hed++]; for(int i=head[u];i!=-1;i=nxt[i]) { int v=to[i]; if(vis[v])continue; vis[v]=vis[u]+1;que[tal++]=v; if(vis[v]>=2)return true; } } return false; } bool Bfs(int s) { for(int i=0;i<n+n;i++) { if(bfs(i))return true; } return false; } char str[N]; int main() { int t,i,j,m,p; scanf("%d",&t); for(int h=0;h<t;h++) { scanf("%d",&n);getchar(); memset(head,-1,sizeof(head));cnt=0; for(i=0;i<n;i++) { gets(str); for(j=0;j<n;j++) { if(str[j]=='P')addedge(i,j); else if(str[j]=='Q')addedge(n+i,n+j); } } if(Bfs(0)) { puts("N"); } else { puts("T"); } } return 0; }
C.朋友
模拟此套题时以为离根隔偶数条边的边要算sg值,反之不要
结果这个思路是错的。。。还以为此题有多大的复杂度呢
再做就知道了,不管根结点与1边隔了多少0边,只要中间隔了0边,要动这条1边,要做偶数次才能消除此链上的所有1边
所以加边只是往边的两侧反转标记,标记是奇数说明操作奇数次,G赢;否则就是偶数次,B赢
单纯的找规律题
#include <bits/stdc++.h> using namespace std; typedef double db; typedef long long ll; typedef unsigned int uint; typedef unsigned long long ull; const db eps=1e-6; const int M=100010; #define lson l, m, rt << 1 #define rson m + 1, r, rt << 1 | 1 #define CLR(a, b) memset(a, b, sizeof(a)) const int N=40010; set<int> s[N]; char fag[N]; int main() { int t,i,j,n,m,p; scanf("%d",&t); for(int h=0;h<t;h++) { memset(fag,0,sizeof(fag)); scanf("%d%d",&n,&m); for(i=0;i<n;i++)s[i].clear(); for(i=0;i<n-1;i++) { int u,v,fl; scanf("%d%d%d",&u,&v,&fl);u--,v--; if(fl==1)fag[v]^=1,fag[u]^=1,s[u].insert(v),s[v].insert(u); } for(i=0;i<m;i++) { int op,x,y,z; scanf("%d",&op); if(op==0) { scanf("%d",&x);x--; if(fag[x]==1)puts("Girls win!"); else puts("Boys win!"); } else { scanf("%d%d%d",&x,&y,&z);x--,y--; set<int>::iterator sit1=s[x].find(y); set<int>::iterator sit2=s[y].find(x); if(sit1!=s[x].end() && z==0) { s[x].erase(sit1);s[y].erase(sit2); fag[x]^=1,fag[y]^=1; } if(sit1==s[x].end() && z==1) { s[x].insert(y);s[y].insert(x); fag[x]^=1,fag[y]^=1; } } } } return 0; }
D.平行四边形
(本渣不会用几何画板,用的画图请见谅)下见解析几何部分:
顺带吐槽一句:你们转发x姐的题解不知道自己算吗
E.扫雷
表示还是太简单了。。转移状态什么的就搞定了
可以用上1行有多少个雷来转移系数
//看看会不会爆int!数组会不会少了一维! //取物问题一定要小心先手胜利的条件 #include <bits/stdc++.h> using namespace std; #pragma comment(linker,"/STACK:102400000,102400000") #define LL long long #define ALL(a) a.begin(), a.end() #define pb push_back #define mk make_pair #define fi first #define se second #define haha printf("haha ") const int maxn = 1e4 + 5; const LL mod = 100000007; LL dp[maxn]; char ch[maxn]; int a[maxn]; int n; int p[3] = {1, 2, 1}; LL solve(){ LL ans = 0; for (int i = 0; i <= 2 && i <= a[1]; i++){ if (a[1] - i > 2) continue; dp[1] = a[1] - i; for (int j = 2; j <= n; j++){ dp[j] = a[j - 1] - dp[j - 1] - dp[j - 2]; } if (dp[n] + dp[n - 1] != a[n]) continue; LL res = 1; for (int j = 1; j <= n; j++){ res = res * p[dp[j]]; if (res > mod) res %= mod; } ans = (ans + res) % mod; } return ans; } int main(){ int t; cin >> t; while (t--){ scanf("%s", ch); n = strlen(ch); bool flag = true; for (int i = 0; i < n; i++){ if ((i == 0 || i == n-1) && ch[i] > '4'){ flag = false; break; } if (ch[i] > '6'){ flag = false; break; } a[i + 1] = ch[i] - '0'; } if (!flag) { printf("0 "); continue; } printf("%I64d ", solve()); } return 0; }
J.最大公约数
严格来说做这题时这根本不是赛时状态。。。这题的题解有人放在async结果一不小心看到题解的一部分
赛时还想着把数列切成3部分:以模结果为0为边界,然后就把自己搞死了
其实此题同j不同i的数之间的差是循环节来的,就是说可以只切成2部分:前面每c[i][j]个数一组求和,用等差数列的方法算,后面n%c[i][j]个直接算,不用优化成o(1)
组内公差不好处理,转组外公差就好解决,毕竟公差正好都是凑够不会被向下取整的整数,还相等
时间复杂度o(t*m^2*log2n) c是辗转相除法次数,不超log2n
#include <bits/stdc++.h> //#include<iostream> using namespace std; typedef double db; typedef long long ll; typedef unsigned int uint; typedef unsigned long long ull; const db eps=1e-6; const int N=700; #define lson l, m, rt << 1 #define rson m + 1, r, rt << 1 | 1 #define CLR(a, b) memset(a, b, sizeof(a)) int gcd[N][N],c[N][N],f[N][N]; int tmp[N]; void calc(int a,int b) { int pc=0,x=a,y=b; while(y>0) { pc++; int t=x%y; x=y; y=t; } gcd[a][b]=x; c[a][b]=pc; f[a][b]=pc*x*x; } int main() { int t,i,j,n,m,p; memset(f,0,sizeof(f)); for(i=1;i<700;i++)for(j=1;j<700;j++)calc(i,j); scanf("%d",&t); for(int h=0;h<t;h++) { scanf("%d%d%d",&n,&m,&p); ll ans=0; for(j=1;j<=m;j++) { for(i=1;i<=j;i++) { ll a1=0; for(int l=0;l<c[i][j];l++)//前c[i][j]个作为等差数列的第1项 { tmp[l]=(i+j*l)*j/f[i][j]%p; a1=(a1+tmp[l])%p; } ll cnt=(n-i)/j;cnt++; ll num=cnt/c[i][j],g=gcd[i][j]; ll d=(j/g*j/g)%p*c[i][j]%p;//不要管组内公差,组外公差才容易处理。这是每c[i][j]个组合起来的结果 ans=(ans+num*(num-1)/2%p*d%p+num*a1%p)%p; ll rem=cnt%c[i][j]; for(int k=0;k<rem;k++)ans=(ans+tmp[k]+num*j/g*j/g%p)%p;//第2部分 } } printf("%I64d ",ans); } return 0; }