沈陽集訓day2
問題 A: 置換
題目描述
negii就是我們要將7(0111)翻轉成14(1110),11(1011)翻轉成13(1101)。
現在我們給定二進制位數k以及n個滿足二進制位數不超過k的數,我們需要輸出對應翻轉後的數的十進制表示
由於讀入量較大,所以n個數由本機隨機生成,具體生成方式如下
int my_rand()
{
Seed=(214013LL*Seed+2531011)&((1<<k)-1);
return Seed;
}
我們會給出初始的Seed,我們會調用n次函數,得到需要翻轉的n個數
我們還會采取特殊的輸出方式,我們將所有答案hash,並輸出最後的值即可
int ans=0;
void my_hash(int x)
{
ans=((long long)ans*233+x)%99824353;
}
我們每得到一個數,進行翻轉後,我們就會調用一次這個函數,其中傳入參數x為翻轉後的數,我們最後輸出ans的值即可。
輸入
共3個數,分為n,k,Seed
輸出
一行,一個整數,表示最後hash值。
樣例輸入
5 3 233
樣例輸出
76005766
提示
數據範圍
對於前50% k<=17
對於前70% k<=20
對於前90% k<=23
對於 100% n<=2k ,k<=25
題解:暴力hash
#include<bits/stdc++.h> using namespace std; const int maxn = 1<<25; int n, k, Seed; int p[maxn+1]; int my_rand() { Seed=(214013LL*Seed+2531011)&((1<<k)-1); return Seed; } int ans=0; void my_hash(int x) { ans=((long long)ans*233+x)%99824353; } int main(){ scanf(View Code"%d%d%d", &n, &k, &Seed); p[0] = 0; for(int i = 1; i <= (1<<25); i++){ int c = p[i>>1]; p[i] = (c>>1) | ( (i&1) << (k-1) ); } for(int i = 1; i <= n; i++){ int now = my_rand(); my_hash(p[now]); } printf("%d\n",ans); }
問題 B: 字符串
題目描述
negii和 starria 是好朋友。他們在一起做字符串遊戲。
我們定義對於一個字符串的翻轉操作:比如翻轉的串為 R,那麽他會將前|R|?1個字符倒序後,插入到該串的最後。舉個例子,串abd進行翻轉操作後,將得到abdba
negii進行了若幹次(可能為 0 次)字符串的翻轉操作。
negii對starria展示出了一個非空串S, S 是一個串 R 的前綴。他想考考starria,初始的串 R 的長度可能是多少。
starria找到了正在參加模擬賽的你,請你來幫她解決這個問題。但聰明的starria發現,所有超過 |S| 的整數都一定是 R 的可能長度,因此你只需要告訴她不超過的 |S| 的 R 的可能長度即可。
輸入
輸入包含多組數據,第一行一個整數 T 表示數據組數。
接下來依次描述每組數據,對於每組數據,一行一個僅由小寫字母組成的非空字符串S。
輸出
對於每組數據,輸出 1 行,從小到大輸出|R|的所有不超過 |S| 的可能值,所有值之間用單個空格隔開。
樣例輸入
3 abcdcb qwqwq qaqaqqq
樣例輸出
4 6 2 3 4 5 6 7
提示
數據範圍
對於40% 保證 ∑|S|≤5×10^2?? 。
對於60% 保證 ∑|S|≤5×10^3?? 。
對於100% 保證 |S|≤106,∑|S|≤5×10^6?? 。
題解:hash暴力匹配前後翻轉的,找開始結束的O1查詢; 或者馬拉車,但是我寫掛了
hash
#include<bits/stdc++.h> using namespace std; const int maxn = 1000005, bas = 233; bool vis[maxn], tag[maxn]; int sh, len, base[maxn], hs1[maxn], hs2[maxn]; char s[maxn], str[maxn]; bool gethash(int l, int ed){ int a = hs1[ed] - hs1[ed-l]*base[l], b = hs2[len-ed+1] - hs2[len-ed+1-l]*base[l]; return a == b; } int cmp(int ed){ int l1 = ed, l2 = len - ed + 1; if(l1 >= l2) if(gethash(l2, ed))return 1; else return -1; if(l1 < l2) if(gethash(l1, ed)){ sh = ed + l1 - 1; return 0; } else return -1; } bool dfs(int k){ if(vis[k])return tag[k]; vis[k] = 1; int pp = cmp(k); if( pp < 0)return tag[k] = 0; if( pp == 0)return tag[k] = dfs(sh); else return tag[k] = 1; } void init(){ base[0] = 1; for(int i = 1; i <= len; i++) base[i] = base[i- 1] * bas , hs1[i] = hs1[i-1] * bas + s[i-1] - ‘a‘ ; for(int i = 1; i <= len; i++) hs2[i] = hs2[i-1] * bas + s[len - i] - ‘a‘; } int main(){ int T; scanf("%d",&T); while(T--){ scanf("%s", s); len = strlen(s); init(); memset(vis, 0, sizeof(vis)); memset(tag, 0, sizeof(tag)); tag[len] = 1; for(int i = 2; i < len; i++) if(!vis[i])dfs(i); for(int i = 1; i <= len; i++) if(tag[i])printf("%d ", i); printf("\n"); } }View Code
manacher
#include<bits/stdc++.h> using namespace std; const int maxn = 1000005; bool vis[maxn], tag[maxn]; int sh, len, p[maxn<<1]; char s[maxn], str[maxn<<1]; int cmp(int ed){ int l1 = ed + 1, l2 = len - ed; if(l1 >= l2) if( p[ed*2+2]/2 >= l2 )return 1; else return -1; if(l1 < l2){ int ll = p[ed*2+2]/2; if(ll < l1)return -1; sh = ed + ll - 1; return 0; } } void manacher(){ memset(p, 0, sizeof(p)); str[0] = ‘$‘; str[1] = ‘#‘; int len1 = strlen(s); for(int i = 0; i < len1; i++){ str[i*2 + 2] = s[i]; str[i*2 + 3] = ‘#‘; } int len2 = len1*2 + 2; int id = 0, maxid = 0; for( int i = 1; i <= len2; i++){ if(maxid > i) p[i] = min(p[id*2 - i], maxid - i); else p[i] = 1; while(str[i - p[i]] == str[i + p[i]])p[i]++; if( p[i] + i > maxid){ id = i; maxid = i + p[i]; } } } bool dfs(int k){ if(vis[k])return tag[k]; vis[k] = 1; int pp = cmp(k); if( pp < 0)return tag[k] = 0; if( pp == 0)return tag[k] = dfs(sh); else return tag[k] = 1; } int main(){ int T; scanf("%d",&T); while(T--){ scanf("%s", s); len = strlen(s); manacher(); memset(vis, 0, sizeof(vis)); memset(tag, 0, sizeof(tag)); tag[len-1] = 1; for(int i = 1; i < len; i++) if(!vis[i])dfs(i); for(int i = 0; i < len; i++) if(tag[i])printf("%d ", i+1); printf("\n"); } }View Code
問題 C: 女神
題目描述
輸入
共一行,一個正整數n
輸出
一個整數,為答案除以1e9+7的余數
樣例輸入
520
樣例輸出
563343175
提示
數據範圍
20 % : n<=300
40 % : n<=2,000
50 % : n<=10,000
70 % : n<=1,000,000
100 % : n<=1,000,000,000
題解:數學題, 遞推公式:ans = n * (n + 1) ^ (n - 2) ;
#include<bits/stdc++.h> using namespace std; const int maxn = 10005; #define ll long long const ll p = 1e9+7; ll pow(ll n){ ll ans = 1, a = 2; for(; n; n>>=1, a = a*a %p) if(n & 1)ans = ans*a% p; return ans; } int main(){ ll n; cin>>n; ll ans = n * (n + 1) % p * pow(n - 2) % p; cout<<ans<<endl; }View Code
沈陽集訓day2